skip to Main Content

I create a React Context like:
context.ts file

import { createContext } from "react";

const Context = createContext({
  error: "",
  setError: () => {},
});

export default Context;

I get a child component which need to set a value into this context:
component.tsx

import Context from MyContext;

function child() {
  const [error, setError] = useState();

 useEffect(() => {
  setError("foo");
});

return(
<Context.Provider value={{error, setError}}>
// Some unrelated stuff 
</Context.Provider>
);

From parent child I try to display context value:

import routes from "routes";

function App() {
  const routing = useRoutes(routes);
  const { error, setError } = useContext(Context);

  useEffect(() => {
console.log("error : ", error);
});

return (
 {routes}
);

routes.tsx:

const routes = [
  {
    path: "/",
    element: <Index />,
  },
];

export default routes;

Index.tsx:

function Index() {
  return <child/>; 
}

export default Index;

I can see the output of console: error :

So the child component never set, or parent component never received new context value.
How to pass context value set from child component, to parent component ? (maybe it’s an issue with routing ? )

2

Answers


  1. The issue here is that the Context.Provider is inside the child component and the parent component is trying to access the context value.

    The context value is not available to the parent because the parent is not wrapped inside the Context.Provider. You need to wrap both components with Context.Provider in order to be able to use it in both.

    Thus:

    App.tsx:

    function App() {
      const [error, setError] = useState("");
      const routing = useRoutes(routes);
    
      useEffect(() => {
        console.log("error : ", error);
      }, [error]);
    
      return (
        <Context.Provider value={{ error, setError }}>
          {routing}
        </Context.Provider>
      );
    }
    

    Child.tsx:

    function Child() {
      const { error, setError } = useContext(Context);
    
      useEffect(() => {
        setError("foo");
      }, []);
    
      return (
        <div>
          // Some stuff 
        </div>
      );
    }
    
    Login or Signup to reply.
  2. Context lets components pass information deep down without explicitly passing props.

    (React official documentation)

    The component which sets the Context up – by using <Context.Provider – needs to be above the one that reads it. Context.Provider needs to be an ancestor (e.g. direct parent) of whatever calls useContext. In your case it’s exactly the opposite.

    You need to swap things around:

    • move <Context.Provider to the parent component
    • move useContext to the child.

    Parent

    import routes from "routes";
    import Context from MyContext;
    
    function App() {
      const [error, setError] = useState();
      const routing           = useRoutes(routes);
    
      useEffect(() => {
        console.log("error : ", error);
      });
    
      return (
        <Context.Provider value={[ error, setError ]}>
          {routes}
        </Context.Provider>
      );
    }
    

    Child:

    import Context from MyContext;
    
    function Child() {
      const [ error, setError ] = useContext(Context);
    
      useEffect(() => {
        setError("foo");
      });
    
      return (
        // Some unrelated stuff
      );
    }
    

    (additionally I swapped

    value={{ error, setError }} to value={[ error, setError ]}

    and const { error, setError } to const [ error, setError ]

    as I’d reccommend to preserve the convetion introduced by useState)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search