React: v16.6.0 or higher Context API not working when child is used in component that provides the context

Created on 4 Jan 2019  路  2Comments  路  Source: facebook/react

I'm using the new context API of react (v16.6.0 or higher) by declaring the public static contextType inside the component that consumes the context.
This is working fine as long as the component that declares the Provider does not directly use a component that consumes the context in it's render() method.

Example:

ParentWithContext

This is the component that creates and provides the context.

export const SomeContext = React.createContext({
  someValue: false
});

export default class ParentWithContext extends Component {
  public render(){
    const contextValue = {someValue: true};
    return (
      <SomeContext.Provider value={contextValue}>
        <ChildOne />
        {this.props.children}
      </SomeContext.Provider>
    );
  }
}

Notice that this component uses ChildOne component (s. right below) in it's render() method.

ChildOne and ChildTwo

These two components simply consume the above context and display it.

export default class ChildOne extends Component {
  public static contextType = SomeContext;
  public render(){
    return (
      <div>
        {`Context of ChildOne: ${this.context.someValue}`}
      </div>
    );
  }
}

export default class ChildTwo extends Component {
  public static contextType = SomeContext;
  public render(){
    return (
      <div>
        {`Context of ChildTwo: ${this.context.someValue}`}
      </div>
    );
  }
}

index.tsx

class App extends Component {

  render() {
    return (
      <ParentWithContext>
        <ChildTwo />
        <ChildOne />
      </ParentWithContext>
    );
  }
}

Running this example will produce following lines:

Context of ChildOne: undefined
Context of ChildTwo: true
Context of ChildOne: undefined

So ChildTwo seems to receive the correct information from this.context, while ChildOne receives nothing.

Now comes the weird part (to me): When you remove the <ChildOne/> from ParentWithContext it suddenly works for both ChildOne and ChildTwo

New ParentWithContext

export default class ParentWithContext extends Component {
  public render(){
    const contextValue = {someValue: true};
    return (
      <SomeContext.Provider value={contextValue}>
        {this.props.children}
      </SomeContext.Provider>
    );
  }
}

New HTML output

Context of ChildTwo: true
Context of ChildOne: true

Running Code

Question

Why is the context API (>=v16.6) not working (using static contextType) when the Provider component directly uses a child component that consumes the context in it's render() function? Is this a bug or a known limitation? Did I miss something?

Additonal information

Using <SomeContext.Consumer> will work as expected.

export default class ChildOne extends Component {
  public render(){
    return (
      <SomeContext.Consumer>
        {context =>
          <div>
          {`Context of ChildOne: ${context.someValue}`}
          </div>
        }
      </SomeContext.Consumer>
    );
  }
}

Of course it's not a solution for this issue but might be a useful information.

Most helpful comment

Hi @Flaneder. I think your problem is related to import statements order. If you print out SomeContext value for ChildOne you'll see undefined:

screenshot 2019-01-05 at 01 21 43

But the same print for ChildTwo will be correct:

screenshot 2019-01-05 at 01 22 10

I think it happens because you import ChildOne before actuall context definition code:

screenshot 2019-01-05 at 01 25 04

The easiest way to fix you problem is just declare context object in separate file. I updated your example here.

All 2 comments

Hi @Flaneder. I think your problem is related to import statements order. If you print out SomeContext value for ChildOne you'll see undefined:

screenshot 2019-01-05 at 01 21 43

But the same print for ChildTwo will be correct:

screenshot 2019-01-05 at 01 22 10

I think it happens because you import ChildOne before actuall context definition code:

screenshot 2019-01-05 at 01 25 04

The easiest way to fix you problem is just declare context object in separate file. I updated your example here.

That's something I would've never thought of..

Was this page helpful?
0 / 5 - 0 ratings