updating a react hook doesn't update in all components

Viewed 364

i have a custom hook that is being used in multiple components...the problem is when updating the hook value from one component it updates the component state but the other components do not update or remount

here is the first component:

import useTranslation from "./customHook";

export default component1 = () => {
  const { t } = useTranslation();
  return <div>{t()}</div>;
};

here is my second component that updates the hook on button click:

import useTranslation from "./customHook";

export default component2 = () => {
  const { t, setLanguage } = useTranslation();
  return (
    <button
      onClick={() => {
        setLanguage(t() === "ar" ? "en" : "ar");
      }}
    >
      {t()}
    </button>
  );
};

and here is the hook itself

import {  useCallback, useState } from "react";

export default function useTranslation() {
  const [language, setLanguage] = useState("ar");
  const [fallbackLanguage, setFallbackLanguage] = useState("en");

  const translate = useCallback(() => {
    return language;
  }, [language]);

  return {
    language,
    setLanguage,
    fallbackLanguage,
    setFallbackLanguage,
    t: translate
  };
}


what I want to achieve is that component2 gets updated or remounted codesandbox :https://codesandbox.io/s/goofy-fast-q39hx?file=/src/customHook.js:0-403

2 Answers

Each component that uses the custom hook has its own state that are not linked together with the other components.

Try to render multiple components and you'll see it clearly !

Hooks do not provide the same state to many components at once. Each time you use the hook in a component, the hook will have its own unique state for each component.

If you want to share states between components, you will need to use Context.

This will work in a similar way to the hook you use now, but will hold state at a higher layer and share it to any components below it that you wish to use it with.

Context lets us pass a value deep into the component tree without explicitly threading it through every component.

//Create a context for the current theme (with "light" as the default).
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    // Use a Provider to pass the current theme to the tree below.
    // Any component can read it, no matter how deep it is.
    // In this example, we're passing "dark" as the current value.
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Assign a contextType to read the current theme context.
  // React will find the closest theme Provider above and use its value.
  // In this example, the current theme is "dark".
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

Change your hook into a context and remember to create a provider and wrap your app in it!

The KEY to remember is that a hook provides SINGLE states to components and context provides SHARED states to components!

Check out the docs for more depth and examples. https://reactjs.org/docs/context.html

Related