Skip to content

React Context API

Howie Reith edited this page Sep 27, 2019 · 9 revisions

This section expands on the previous by adding React Context API to the Name That Pirate game. To prepare for the next exercise, do the following:

Exercise 3:

  1. Navigate to the context-api directory and run the following commands:

    npm install
    npm start
  2. Once the app loads, notice that the behavior is identical to the previous version.

  3. Open the context-api\src\AppProvider.js file and study its contents. This is the only file that was added to the project.

  4. Examine the changes made to the App.js, GameBoard.js, and Score.js files.

Important Concepts

React Context API allows data to be shared between components that do not have a parent/child relationship. It is the state management tool we currently use in "Marauder" and one which has grown in popularity since its release in late 2018. If you've ever used themes in the popular Styled Components tool for React, that library makes use of the Context API.

In the previous app, in order for the Score and GameBoard to share data, the App component had to take responsibility for managing the correct and incorrect counts. This code is shown below.

```javascript
// state-api App.js
...
  constructor(props) {
    ...
    this.state = {
      correct: 0,
      incorrect: 0,
    };
    ...
  }

  handleCorrectAnswer() {
    this.setState({
      correct: this.state.correct + 1,
    });
  }

  handleIncorrectAnswer() {
    this.setState({
      incorrect: this.state.incorrect + 1,
    });
  }

  render() {
  ...
        <GameBoard
          onCorrectAnswer={this.handleCorrectAnswer}
          onIncorrectAnswer={this.handleIncorrectAnswer}
        />
        <Score correct={this.state.correct} incorrect={this.state.incorrect} />
  ...
  }
  ...
```

Instead of relying on the highest-level component to keep track of things, React Context API creates a context that can be wrapped around the components involved. It's an approach best used in applications where you have several components that use and/or modify the same data but are separately and deeply nested within the component tree.

Here is the code for our context provider in our Pirate game:

``` javascript
// App.js
export const AppContext = React.createContext();

export default class AppProvider extends React.Component {
  state = {
    correct: 0,
    incorrect: 0,
    incCorrect: () => {
      this.setState({correct: this.state.correct + 1});
    },
    incIncorrect: () => {
      this.setState({incorrect: this.state.incorrect + 1});
    },
  };

  render() {
    return (
      <AppContext.Provider value={this.state}>
        {this.props.children}
      </AppContext.Provider>
    );
  }
}
```

The AppProvider defined above gets wrapped around GameBoard and Score so that they can share state.

``` javascript
// App.js
...
<AppProvider>
  <GameBoard />
  <Score />
</AppProvider>
...
```

The Score component uses AppContext.Consumer to display state contained in the context.

``` javascript
// Score.js
...
<AppContext.Consumer>
  {context => context.correct}
</AppContext.Consumer>
...
```

The GameBoard component uses the functions defined in the context to update state stored in the context.

``` javascript
// GameBoard.js
...
handleAnswerSelected(pirate, context) {
...
    context.incCorrect();
...
    context.incIncorrect();
...
}
...
<AppContext.Consumer>
  {context => {
    return this.state.turn.possiblities.map(p => (
      <Answer
        key={p.name}
        pirate={p}
        disabled={p.disabled}
        onSelected={p => this.handleAnswerSelected(p, context)}
      />
    ));
  }}
  ...
```

Exercise 4:

  1. Add a button to the Score component in the location shown below.
           <AppContext.Consumer>
             {context => context.incorrect}
           </AppContext.Consumer>
         </span>
       </span>
     </h3>
     // HERE THERE BE A BUTTON
   </div>
  1. Add a click handler to the new button that resets the correct and incorrect counts to 0

Pros

  • Simple
  • Little to no hidden logic, i.e., no "magic."
  • Data sharing is possible without a Parent/Child relationship
  • Built into React negating the need for external libraries thus preventing conflicts and update woes.

Cons

  • The context can become unwieldy as it grows.

Next

Clone this wiki locally