Skip to content

Instantly share code, notes, and snippets.

@Muzammil-cyber
Last active May 23, 2024 20:53
Show Gist options
  • Save Muzammil-cyber/7ee60a480dcf6f8e6b56dbad6348f777 to your computer and use it in GitHub Desktop.
Save Muzammil-cyber/7ee60a480dcf6f8e6b56dbad6348f777 to your computer and use it in GitHub Desktop.

Your very own React State Management

Building our store

function createStore<T>({ initialState }: { initialState: T }) {
  let subscribers: Listener[] = [];
  let state = initialState;

  const notifyStateChanged = () => {
    subscribers.forEach((fn) => fn());
  };

  return {
    subscribe(fn: Listener) {
      subscribers.push(fn);
      return () => {
        subscribers = subscribers.filter((listener) => listener !== fn);
      };
    },
    getSnapshot() {
      return state;
    },
    setState(newState: T) {
      state = newState;
      notifyStateChanged();
    },
  };
}

To use the store in react we'll create createUseStore which is a helper that wraps createStore and useSyncExternalStore in a convenient way:

export function createUseStore<T>(initialState: T) {
  const store = createStore({ initialState });
  return () => [useSyncExternalStore(store.subscribe, store.getSnapshot), store.setState] as const;
}

Using the store

Counter component:

export const useCountStore = createUseStore(0);
import { useCountStore } from "./countStore";

function Counter() {
  const [count, setCount] = useCountStore();

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

For more info

Read more about useSyncExternalStore in the react docs.

To see the implementation of the concepts discussed in this article in action, check out tinystate-react here. This library is built using the approach described in this tutorial, allowing you to dive deeper into the code and examples.

import { useSyncExternalStore } from 'react';
export type Listener = () => void;
function createStore<T>({ initialState }: { initialState: T }) {
let subscribers: Listener[] = [];
let state = initialState;
const notifyStateChanged = () => {
subscribers.forEach((fn) => fn());
};
return {
subscribe(fn: Listener) {
subscribers.push(fn);
return () => {
subscribers = subscribers.filter((listener) => listener !== fn);
};
},
getSnapshot() {
return state;
},
setState(newState: T) {
state = newState;
notifyStateChanged();
},
};
}
export function createUseStore<T>(initialState: T) {
const store = createStore({ initialState });
return () => [useSyncExternalStore(store.subscribe, store.getSnapshot), store.setState] as const;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment