DEV Community

Alex
Alex

Posted on

Sharing state between unrelated React components

Want to show how you can share any serializable data between React components, e.g. client components in NextJS.

We have few unrelated components:

Example app UI

Let's create an object that will contain initial state

export const state: { count: number } = { count: 0 };
Enter fullscreen mode Exit fullscreen mode

We can store data in a WeakMap, state will be a key to access it. Also, will need a subscribers array.

const stateMap = new WeakMap<object, object>();
const subscribers: (() => void)[] = [];
Enter fullscreen mode Exit fullscreen mode

Now let's write a hook to subscribe to data changes.

export function useCommonState<T extends object>(stateObj: T) {
  // more efficient than `useEffect` since we don't have any deps
  React.useInsertionEffect(() => {
    const cb = () => {
      const val = stateMap.get(stateObj);
      _setState(val!);
    };
    // subscribe to events
    subscribers.push(cb);

    return () => {
      subscribers.slice(subscribers.indexOf(cb), 1);
    };
  }, []);
}
Enter fullscreen mode Exit fullscreen mode

Now let's add logic related to get and set state

  // all instances of hook will point to same object reference
  const [state, _setState] = React.useState<typeof stateObj>(() => {
    const val = stateMap.get(stateObj) as T;
    if (!val) {
      stateMap.set(stateObj, stateObj)
      return stateObj
    }
    return val
  });

  const setState = React.useCallback((newVal: object) => {
    // update value
    stateMap.set(stateObj, newVal);
    // notify all hook instances
    subscribers.forEach((sub) => sub());
  }, []);

  return { state, setState };

Enter fullscreen mode Exit fullscreen mode

And now can use it in 3 components like

import { state as myState } from './state';
//...

const { state, setState } = useCommonState(myState);

<button
  onClick={() => setState({ count: state.count + 1 })}
  className="p-2 border"
>
  +
</button>
// ...
Component A<div>Count: {state.count}</div>
Enter fullscreen mode Exit fullscreen mode

Final app

You can see how it works here https://stackblitz.com/~/github.com/asmyshlyaev177/react-common-state-example
Or here https://codesandbox.io/p/github/asmyshlyaev177/react-common-state-example/main
Or in github https://github.com/asmyshlyaev177/react-common-state-example

Check out my library for NextJS based on this principle https://github.com/asmyshlyaev177/state-in-url

Tnx for reading.

Top comments (0)