Robo Robok
Robo Robok

Reputation: 22815

React: Why isn't my context value updated?

I'm playing with React Context API. I created a simple component:

import React, { createContext, useContext } from 'react';

const MyContext = createContext(1);

const MyComponent = () => (
    <>
        <p>{useContext(MyContext)}</p>
        <MyContext.Provider value={2}>
            <p>{useContext(MyContext)}</p>
        </MyContext.Provider>
    </>
);

export default MyComponent;

I'm getting two <p>1</p>. Why isn't the second context updated with 2? Am I using useContext() incorrectly?

Upvotes: 4

Views: 115

Answers (2)

cbr
cbr

Reputation: 13662

You'll need to render another component inside the context provider to get the value of 2. As useContext's documentation states:

Accepts a context object (the value returned from React.createContext) and returns the current context value for that context. The current context value is determined by the value prop of the nearest <MyContext.Provider> above the calling component in the tree.

Emphasis added. The important point is that it doesn't matter where you call useContext inside the component - what matters is where that component where it's called in is located in the tree.

import React, { createContext, useContext } from "react";

const MyContext = createContext(1);

const ChildComponent = () => (
  <p>{useContext(MyContext)}</p>
)

const MyComponent = () => (
  <>
      <p>{useContext(MyContext)}</p>
      <MyContext.Provider value={2}>
        <ChildComponent/>
      </MyContext.Provider>
  </>
);

export default MyComponent;

Upvotes: 3

Codebling
Codebling

Reputation: 11397

You must use a separate Component to get Context to work.

I've filed a bug about this; see https://github.com/facebook/react/issues/18629

Simply split the code using the Context into a different Component.

const Inner = () => (
    <p>{useContext(MyContext)}</p>
);

const MyComponent = () => (
    <>
        <p>{useContext(MyContext)}</p>
        <MyContext.Provider value={2}>
            <Inner />
        </MyContext.Provider>
    </>
);

That should fix it.

Upvotes: 3

Related Questions