Reuse React hooks in state sharing
Tags: usebetween, react, webdev, javascript
Published: 2021-01-21 11:45:15

Hi guys, today I'm going to talk about how to complete your code with one hook that will complete the puzzle!

The release of React 16.8 was a gift and a blessing, hooks were a great tool for managing the state of components. And having met with amicability, the community began to create new hooks based on standard ones for asynchronous operations, for interacting with external logic, and many many others.

> Hooks let you use state and other React features without writing a class. 
> You can also build your own Hooks to **share reusable stateful logic between components**. [*(React website)*](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html#what-are-hooks)

But (I'm sure) it became a chagrin for everyone that hooks can only store data at the component level. And therefore components can share their state only with children.

And that's the problem.

We have enough hooks to describe any logic, but there is no way to use their state together between a group of unrelated components.

You can see that Recoil, Redux, MobX, and the standard React hooks do the same thing - managing reactive state.
But why do we need to use in our applications a way of describing logic on hooks in components and on an external application state management system?

I suggest you try the simplest way to share the state described in hooks with other unrelated components on the page.

[`useBetween`](https://github.com/betula/use-between)

And this is just one hook, with the only one call argument - a custom hook, the result of which will be shared by everyone.

For example, let's describe a custom hook that supplies a hash from the browser's address bar. The hook subscribes to changes to the browser hash through the `window` event.

```javascript
// router.shared.ts
import { useState, useCallback, useEffect } from "react";
import { useBetween } from "use-between";

const useRouter = () => {
  const [hash, setHash] = useState("");

  const syncHash = useCallback(() => {
    setHash(window.location.hash);
  }, [setHash]);

  useEffect(() => {
    syncHash();
    window.addEventListener("hashchange", syncHash);
    return () => {
      window.removeEventListener("hashchange", syncHash);
    };
  }, [syncHash]);

  return {
    hash
  };
};

export const useSharedRouter = () => useBetween(useRouter);
```

In the last line of the example, we used a call to `useBetween` passing a custom `useRouter` hook as an argument, and thus created a new `useSharedRouter` hook - a shared router for all components that will use it.

```javascript
const Hash = () => {
  const { hash } = useSharedRouter();
  return (
    <p>Location hash: {hash}</p>
  )
}

export const App = () => (
  <>
    <Hash />
    <Hash />
    <Hash />

    <a href="#hash-1">hash-1</a>
    <a href="#hash-2">hash-2</a>
  </>
)
```
[![Edit Counter with useBetween](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/shared-state-with-usebetween-63ul4?file=/src/App.js)

In this example, the router will be created once and will be used for all the `Hash` components. Every time the hash of the navigation bar address changes, all components using `useSharedRouter` will be updated!

We used the standard React hooks that are familiar and understandable to everyone to create a shared state between any components using just one external hook `useBetween`.

Everything will be installed simply `npm i use-between` and you can use and enjoy, and for my taste, the easiest way to share the state in React!

If you like this idea and would like to use it, please put star in github. It will be your first contribution!

{% github betula/use-between %}