DEV Community

Cover image for Reuse React hooks in state sharing
Slava Birch
Slava Birch

Posted on • Edited on

Reuse React hooks in state sharing

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)

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

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.

// 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);
Enter fullscreen mode Exit fullscreen mode

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.

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>
  </>
)
Enter fullscreen mode Exit fullscreen mode

Edit Counter with useBetween

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 logo betula / use-between

Sharing state between React components

use-between

npm version build status npm bundle size code coverage typescript supported 100k+ downloaded

When you want to separate your React hooks between several components it's can be very difficult, because all context data stored in React component function area If you want to share some of state parts or control functions to another component your need pass It thought React component props. But If you want to share It with sibling one level components or a set of scattered components, you will be frustrated.

useBetween hook is the solution to your problem 😚

import React, { useState, useCallback } from 'react';
import { useBetween } from 'use-between';
const useCounter = () => {
  const [count, setCount] = useState(0);
  const inc = useCallback(() => setCount(c => c + 1), []);
  const dec = useCallback(() => setCount(c
…
Enter fullscreen mode Exit fullscreen mode

Top comments (0)