9

I wrap my Home component in the following layout:

export const DataContext = React.createContext({});

const Layout: React.FunctionComponent = (props) => {
  const data = {title: "abc", description: "def"};
  
  return (
    <DataContext.Provider value={data}>
        {props.children}
    </DataContext.Provider>
  );
};

I would like to use useContext hook in my Home component, but it returns an empty object:

const Home: React.FunctionComponent = () => {
  const content = React.useContext(DataContext);

  return (
    <Layout>
       // content data goes here
    </Layout>
  );
};

I suspected that this is because I define context variable outside of Layout wrapper, which contains context provider, so it falls back to the default value of the context that I defined (an empty object). However, even if I console log the useContext hook inside the layout provider, it also returns an empty object:

const Home: React.FunctionComponent = () => {
  const content = React.useContext(DataContext);

  return (
    <Layout>
      {console.log(React.useContext(DataContext))}
    </Layout>
  );
};

Any idea why?

1
  • Please make those Stack Snippets runnable (here's how), or just use code blocks. Don't use Stack Snippets as code blocks. Commented Feb 19, 2019 at 18:34

3 Answers 3

12

useContext will get the value from the Provider closest to it up the tree. Your Layout is inside Home, which will make the Provider below it in the tree.

You could make Home a child to Layout instead to see it working.

Example

const DataContext = React.createContext({});

const Layout = props => {
  const data = { title: "abc", description: "def" };

  return (
    <DataContext.Provider value={data}>{props.children}</DataContext.Provider>
  );
};

const Home = () => {
  const content = React.useContext(DataContext);

  return <div>{JSON.stringify(content)}</div>;
};

function App() {
  return (
    <Layout>
      <Home />
    </Layout>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Sign up to request clarification or add additional context in comments.

Comments

3

Your Hypothesis that useContext provides an empty object when used outside of Layout is indeed correct. If there is no Provider in the hierarchy then useContext returns the default value provided to React.createContext

Also you can only use React hooks at the start of functional components and not within rendering. So if you write your code like below you will be able to correctly log context value

const Content: React.FunctionComponent = () => {
   const content = React.useContext(DataContext);
   console.log(content);
   return (
      <div>Content</div>
   )
}
const Home: React.FunctionComponent = () => {

  return (
    <Layout>
      <Content />
    </Layout>
  );
};

Working demo

Comments

1

Well, I was facing same kind of issue and after a lot of googling I find out that whenever our page refreshes it set the context value to its default.

So if you are using tag or somthing like that for navigation or something which refreshes the page then use tag from react-router-dom or instead.

This works for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.