2

I have two questions about the new React Context-api:

  1. The React docs has the following example Updating context from a nested component. Is there some specific reason the toggleTheme-function is declared in the constructor (and not as a class method)?

import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    // State also contains the updater function so it will
    // be passed down into the context provider
    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }

  render() {
    // The entire state is passed to the provider
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

function Content() {
  return (
    <div>
      <ThemeTogglerButton />
    </div>
  );
}

ReactDOM.render(<App />, document.root);
  1. In lot of the examples the Provider-component has the state of a high-up -component as its value (just like in the above example). This means that every time I want to update the Context-value, I need to update the state of the high-up -component. This means that the high-up -component re-renders as the state is updated, which in turn means that all of its child-components also re-render. But all I wanted was for the Consumer-components listening to that Provider-component to re-render. Now basically the whole app re-renders everytime I update the Context-value...Am I missing something?
Yellowhill
  • 115
  • 6

1 Answers1

1

toggleTheme is passed as a callback and should be bound to correct this. If it was class prototype method, it would requirethis.toggleTheme = this.toggleTheme.bind(this) in constructor any way. See this related question.

As the documentation states,

All Consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes. The propagation from Provider to its descendant Consumers is not subject to the shouldComponentUpdate method, so the Consumer is updated even when an ancestor component bails out of the update.

A component that contains Provider (App) should be re-rendered to provide new value, while its descendants shouldn't. In this example its direct children (Content) could be PureComponent to prevent unnecessary re-renders in entire hierarchy. There won't be significant performance improvements for a context that affects entire application like theme context.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565