React: contextType apparently not working in dev mode server side rendering

Created on 8 Feb 2019  路  8Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
Crash during server render due to this.context being undefined. Bug only happens in SSR, and only in dev mode react. Issue appears neither in browser renders, nor in production mode server renders.

note: Using https://reactjs.net/ for c# server-side rendering, with bundled-in version of react disabled (so using the same version of react as the client bundle)

(simplified) application structure

// root component
const {Provider, Consumer} = createContext({});
const Root = props => return <Provider value={props.notNull}>{props.children}</Provider>;

// consumer
class ConsumingComponent extends Component {
  static contextType = Consumer;

  render() {
    if (this.context.someValue) return null;
    return <div/>;
  }
}

// render tree
<Root>...<ConsumingComponent/>...</Root>

// output of server render
JsRuntimeException: TypeError: unable to get property 'someValue' of undefined or null reference.

What is the expected behavior?
this.context in the consuming component should be the value passed to the Provider, and not undefined.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

The bug, as best as I can pin down, appeared in 16.6.3. The code works in 16.6..1, and 16.6.2 is listed as a broken release in the changelog.

Component API

All 8 comments

The issue _could_ be that you are providing the Consumer as the static contextType value. Instead static contextType should be assigned the entire context object:

const context = createContext({});
const {Provider, Consumer} = context;
class ConsumingComponent extends Component {
  static contextType = context; // assign `context` here, not `Consumer`

  render() {
    if (this.context.someValue) return null;
    return <div/>;
  }
}

I think there should be a warning for this, however it may only be for the client side renderer (i.e. it might not warn within react-dom/server, if that is what the c# rendering implementation uses).

@hamlim Good catch.

That's a bit unfortunate then, I didn't expect I'd have to expose the entire context object. In my setup, I expose the context consumer for other components to use, but Root in the example is the only thing which should ever use the provider.

This still seems like a bug to me, I'd expect consumers of a context to use context.Consumer, even if they are using contextType.

This is intentionally unsupported but the warning seems necessary.

So is the only solution to break encapsulation, and export the whole context object then? Is there any other alternative?

@gaearon we currently warn only when passing Context.Provider, should we extend that to also warn for Context.Consumer?

So is the only solution to break encapsulation, and export the whole context object then?

In longer term we might change the API a little bit for now, yes.

Ok, thanks for the information.

Was this page helpful?
0 / 5 - 0 ratings