Passing Props with Context

Posted on October 3rd 2020 in React by Pim Debaere.

Passing Props with Context

In most applications properties are passed, from parent to child, so they can be used some levels deeper. This can sometimes seem inconvenient, especially when you have to pass properties to a lot of components. Thanks to React's Context API, this is easy to avoid.

Context API

An example: your application has two possible themes, namely a "light" and a "dark" theme. It is therefore logical that all components use the same theme, so we give pass this property from our main component (App).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class App extends Component {
  render() {
    return <Menu theme="light" />;
  }
}

function Menu(props) {
  return (
    <div>
      <ThemedButton theme={props.theme} />
      <ThemedButton theme={props.theme} />
      <ThemedButton theme={props.theme} />
    </div>
  );
}

class ThemedButton extends Component {
  render() {
    return <Button theme={this.props.theme} />;
  }
}
Fig. 1 – Passing props from parent to child.

Note in particular that we have to provide the same property for each ThemedButton. So let's take a look at the Context API to do this more elegantly. There are four things we should use.

  1. React.createContext: components subscribing to a particular context object will read the values as they are currently in the closest Provider object in the parent tree.
  2. Context.Provider: each Context has a provider that components can subscribe to if they want to use it. All components that use this Provider will be rendered again if they change.
  3. Class.contextType: this property allows the component to consume the nearest value.
  4. Context.Consumer: a component that subscribes to a context is seen as a consumer.

Knowing this, we can rework the example above and get the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Create the context and set the default value of the theme (in this case "dark").
const ThemeContext = React.createContext('dark');

class App extends Component {
  render() {
    // Make App the provider of the context, so every child component
    // can read the properties. Note that the default value is overridden
    // with "light" - you can omit this if you want to use the default.
    return (
      <ThemeContext.Provider value="light">
        <Menu />
      </ThemeContext.Provider>
    );
  }
}

function Menu() {
  // We don't have to pass the theme property further down explicitly.
  return (
    <div>
      <ThemedButton />
      <ThemedButton />
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Assign a contextType to read the current theme context.
  // React will find the closest theme Provider above and use its
  // value - in this case "light".
  static contextType = ThemeContext;

  render() {
    return <Button theme={this.context} />;
  }
}
Fig. 2 – Defining props and consume them using Context.