/archa

Lightweight solution for to create optimised custom context.

Primary LanguageTypeScriptMIT LicenseMIT

Archa

Lightweight solution to create custom React context. Build with typescript, untop useContext and useSyncExternalStore.

Demo

Install it with :

npm i archa

To create your custom context use the createStore function. It takes 2 arguments:

  • initialSate, an object with your states.
  • dispatch (optional), a callback exposing set and get methods to create a list of functions to mutate your states.
const { Provider, useStore } = createStore({
  string: ''
});

and return:

  • Provider
  • useStore, expose all state and a setStore method. Trigger a rerender of your component only when one of the returned state is mutate. If dispatch were provided setStore will not be expose.
  • useDispatch, expose all dispatch functions
  const [state1, setStore] = useStore((store) => [store.state1 store.setStore]);
  const function1 = useDispatch((dispatch) => dispatch.function1);
  ...
  setStore(({ string }) => ({ string: newString })

To Do

  • [] Add a way to get selectors value.
    • by changing useDispatch into useActions (name WIP)
    • by creating a new useSelector hook. If so, should useDispatch use return value to update the store instead of using the set method ?
  • [] Make the Provider be able to take value (Partial<T_Store>).
  • [] Add test.

Example without dispatch

import { createStore } from 'archa';

const { Provider, useStore } = createStore({
  count: 0,
});

function Count() {
  const setStore = useStore((store) => store.setStore);

  return (
    <>
      <button onClick={() => setStore(({ count }) => ({ count: count + 1 }))}>
        Increment count
      </button>
      <button onClick={() => setStore(({ count }) => ({ count: count - 1 }))}>
        Decrement count
      </button>
    </>
  );
}

function CountDisplay() {
  const count = useStore((store) => store.count);

  return <span>{`The current count is ${count}.`}</span>;
}

export function Counter() {
  return (
    <Provider>
      <CountDisplay />
      <Count />
    </Provider>
  );
}

Example with dispatch

import { createStore } from 'archa';

const { Provider, useStore, useDispatch } = createStore(
  {
    count: 0,
  },
  (set, get) => ({
    addCount: () => {
      const { count } = get();
      set({ count: count + 1 }):
    },
    removeCount: () => {
      const { count } = get();
      set({ count: count - 1 }):
    }
  }),
);

function Count() {
  const [ addCount, removeCount ] = useDispatch((dispatch) => [
    dispatch.addCount, dispatch.removeCount
  ]);

  return (
    <button onClick={addCount}>
      Increment count
    </button>
    <button onClick={removeCount}>
      Decrement count
    </button>
  );
}

function CountDisplay() {
  const count = useStore((store) => store.count);

  return (
    <span>{`The current count is ${count}.`}</span>
  );
}

export function Counter() {
  return (
    <Provider>
      <CountDisplay />
      <Count />
    </Provider>
  );
}