Skip to content

nested contexts don't unwind correctly when server side rendering #12984

@ericsoderberghp

Description

@ericsoderberghp

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

bug

What is the current behavior?

When different contexts are nested, as in they have different types, they do not unwind correctly when rendering via renderToString().

Here is a snippet that demonstrates the issue:

import React from 'react';
import { renderToString } from 'react-dom/server';

const valueA = { letter: 'A' };
const valueB = { letter: 'B' };
const LetterContext = React.createContext(valueA);
const NumberContext = React.createContext(undefined);

const html = renderToString((
  <LetterContext.Provider value={valueA}>
    <NumberContext.Provider>
      <LetterContext.Consumer>
        {letterValue => (
          <div>
            {letterValue.letter}
            <LetterContext.Provider value={valueB}>
              <LetterContext.Consumer>
                {innerValue => <div>{innerValue.letter}</div>}
              </LetterContext.Consumer>
            </LetterContext.Provider>
          </div>
        )}
      </LetterContext.Consumer>
      <LetterContext.Consumer>
        {value => <div>{value.letter}</div>}
      </LetterContext.Consumer>
    </NumberContext.Provider>
  </LetterContext.Provider>
));

console.log(html);

This results in:

          value.letter
                ^

TypeError: Cannot read property 'letter' of undefined
    at Object.children (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/tools/example.js:25:31)
    at ReactDOMServerRenderer.render (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/node_modules/react-dom/cjs/react-dom-server.node.development.js:2462:55)
    at ReactDOMServerRenderer.read (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/node_modules/react-dom/cjs/react-dom-server.node.development.js:2325:19)
    at renderToString (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/node_modules/react-dom/cjs/react-dom-server.node.development.js:2697:25)
    at Object.<anonymous> (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/tools/example.js:9:14)
    at Module._compile (internal/modules/cjs/loader.js:678:30)
    at loader (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/ericsoderberg/Documents/git/grommet2/grommet-icons-site/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (internal/modules/cjs/loader.js:589:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)

What is the expected behavior?

When context providers are nested, they should correctly unwind such that the contexts return the correct value at each level. No exception should be generated and the output should be:

<div>A<div>B</div></div><div>A</div>

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

This was uncovered using version 16.4.0 of react-dom on OSX using node v10.1.0.

This only shows up when using renderToString(). It works as expected in the browser.

** Note **

I wonder if this might be due to the following snippet of react-dom-server.node.development.js. Where the previous provider added to the stack is assumed to have the same type as the provider being popped.

    var context = provider.type._context;
    if (this.providerIndex < 0) {
      context._currentValue = context._defaultValue;
    } else {
      // We assume this type is correct because of the index check above.
      var previousProvider = this.providerStack[this.providerIndex];
      context._currentValue = previousProvider.props.value;
    }

I am investigating further and hope to provide a pull request soon.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions