npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

domein

v0.5.1

Published

Just another juicy state manager lib for your js apps.

Downloads

2

Readme

domein

Just another juicy state manager lib for your js apps.

Heavily inspired by redux obviously.

🎉 Features

Why domein over redux or mobx or whatever

  • Always async, no more thunks or whatever
  • Domain based
  • Dead simple API
  • No more dispatch and other stuff, just plain functions and objects
  • Middlewares
  • This lib really loves TypeScript
  • You can control actions flow using only async/await and Promise.all

⚙ Install

# npm
npm i domein

# yarn
yarn add domein

🔍 Usage

Basic state management

// ./state/index.ts
import { create } from 'domein';
import mydomain from './mydomain';

export const state = create({
  mydomain,
});
// ./state/mydomain/index.ts
import { domain } from 'domein';

interface IState {
  value: number;
}

function initialstate(): IState {
  return {
    value: 0,
  };
}

function actions() {
  return {
    decrement,
    increment,
    set,
    setAsync,
  }
}

function decrement(state: IState) {
  return {
    value: state.value - 1,
  }
}

function increment(state: IState) {
  return {
    value: state.value + 1,
  }
}

function set(state: IState, value: number) {
  return { value };
}

async function setAsync(state: IState, value: number) {
  // becase reasons
  return new Promise(resolve =>
    setTimeout(
      () => resolve({ value }),
      100
    )
  );
}

export default domain(initialstate, actions);;
// ./app.ts
import { state } from './state';

const { get, actions } = state;

await actions.mydomain.set(10)
await actions.mydomain.decrement()
await actions.mydomain.decrement()
await actions.mydomain.increment()
get() // { mydomain: { value: 9 } }

Composing multiple actions

Since an action is a function, you can compose them as you want.

import { domain } from 'domein';
import * as api from './api';

interface IState {
  content: string;
  title: string;
  wordcount: number;
}

function actions() {
  return {
    load,
    setWordCount,
  }
}

function initialstate() {
  return {
    content: '',
    title: '',
    wordcount: 0,
  };
}

const myblogpost = domain(initialstate, actions);

async function load(state: IState) {
  const newstate = await api.load();
  return setWordCount({... state, ...newstate});
}

function setWordCount(state: IState) {
  return {
    ... state,
    wordcount: state.content.match(/\S+/g),
  }
}

Actions flow

You could sometimes have a particular scenario where you want some actions to be run in parallels or in waterfall.

To control actions flow, you have to simply create a new function which will await single actions

very important for parallel actions

Parallel actions could lead to wrong state merging. To prevent this behaviour, you will have to merge domain's state by excluding properties which will be updated in parallel

example

// state/index.ts
import { create, domain } from 'domein';

interface IState {
  userscount: number;
  rolescount: number;
  loading: boolean;
  users: IUser[];
  roles: IRole[];
}

function initialstate(): IState {
  return {
    loading: false,
    roles: [],
    rolescount: 0,
    users: [],
    userscount: 0,
  };
}

function actions() {
  return {
    loadroles,
    loadusers,
    setloading,
  }
}

async function loadusers(state: IState) {
  const users = await api.loadusers();
  const userscount = users.length;
  // done this in order to avoid overriding of roles and rolescount
  const { loading } = state;

  return {
    loading,
    users,
    userscount,
  };
}

async function loadroles(state: IState) {
  const roles = await api.loadroles();
  const rolescount = roles.length;
  // done this in order to avoid overriding of users and userscount
  const { loading } = state;

  return {
    loading,
    roles,
    rolescount,
  };
}

function setloading(state: IState, loading: boolean) {
  return {
    ... state,
    loading,
  };
}

const mydomain = domain(initialstate, actions);

export default create({ mydomain });
// ./otherfile.ts
import state from './state';

export async function loadseries() {
  const { mydomain } = state.actions;
  await mydomain.setloading(true);
  await mydomain.loadusers();
  await mydomain.loadroles();
  await mydomain.setloading(false);
}

export async function loadparallel() {
  const { mydomain } = state.actions;
  await mydomain.setloading(true);
  Promise.all([ mydomain.loadusers(), mydomain.loadroles() ]);
  await mydomain.setloading(false);
}

Creating middlewares

import { build, MiddlewareFn } from 'domein';
import mydomain from './mydomain';

function logger(): MiddlewareFn {
  return message => {
    const {
      action,
      domain,
      state,
    } = message;
    
    console.log(
      `[${domain}][${action}]`,
      'previous', state.prev,
      'next', state.next,
    );
  
    return nextstate;
  }
}

const state = build({ mydomain }, logger);

state.actions.mydomain.set(10) // logs: [update][mydomain][set] previous { value: 0 } next { value: 10 }

📖 Docs

create

The create function simply creates a new state.

It accepts one parameter which is an object of key/value pairs, where keys are domain names and values are domains

A created state, returns an object with one property and two functions:

  • actions, which are the subscribed actions, organized by domain
  • get, returns current state
  • subscribe, subscribes a function to state changes. Every state change will trigger it, telling the subscribed function which domain did update and giving it the new state
const state = create({ mydomain });

state.subscribe(message => console.log(message.domain, message.state));

state.actions.mydomain.set(10) // logs: 'mydomain', { value: 10 }

domain

To create a domain use it's related function.

This function accepts two functions, the first which returns the initial domain state and the second which returns an object containing actions

import { domain } from 'domein';

// domain's state interface
interface IDomainState { }

function initialstate(): IDomainState {
  return { }
}

function actions() {
  return { }
}

export default domain(initialstate, actions);

️❤️ Contributing

Every contribution is really welcome!

If you feel that something can be improved or should be fixed, feel free to open an issue with the feature or the bug found.

If you want to fork and open a pull request (adding features or fixes), feel free to do it. Remember only to use the master branch as a base.

If you plan adding a new feature, please prefix the branch with the feat/branchname.

If you plan fixing something, please prefix the branch with the fix/branchname.

If you plan refactoring something, please prefix the branch with the refactor/branchname.

If you adding something which does not involve the runtime behavious, please prefix the branch with the chore/branchname.

Read the contributing guidelines

📃 Licence

Read the licence