React Context API: Managing State with Ease

Translator: OFED

Managing state is easy with the latest React Context API. Now learn how it differs from Redux and how it is used.

Overview: The React Context API is not new to the React ecosystem. However, some improvements were made in React 16.3.0. These improvements were so dramatic that they significantly reduced our need for Redux and other advanced state management libraries. In this article, you’ll learn how the React Context API replaces Redux for state management for small applications with a practical tutorial.

Redux quick review

Before getting to the point, let’s take a quick look at Redux so we can compare the two. Redux is a state-friendly JavaScript library. Redux itself has nothing to do with React. Many developers from around the world have chosen to use Redux in popular front-end frameworks such as React and Angular.

To clarify, in this article, state management refers to handling state changes triggered by specific events that occur in a single page application (SPA). For example, a button click event or an asynchronous message from the server can trigger a change in application state.

In Redux, you should pay particular attention to the following points:

  1. The state of the entire app is stored in a single object (called a data source).
  2. To change the state, you need to trigger it with the Dispatch methodactionsActions describe what should happen.
  3. In Redux, you cannot change an object’s properties or change an existing array; you must always return a new object or array.

If you’re not familiar with Redux and you want to learn more, check out Redux’s practical tutorial.

React Context API Guide

The React Context API provides a way to pass data through a tree of components rather than through layers of props properties. In React, data is typically passed from parent to child components as a property.

Using the latest React Context API requires three key steps:

  1. Pass the initial state toReact.createContext. This method returns a file withProviderConsumerThe object.
  2. useProviderThe component wraps around the outermost layer of the component tree and receives a value attribute. The value attribute can be any value.
  3. useConsumerComponent, in the component treeProviderA subset of the state can be retrieved anywhere within the component.

As you can see, the concepts involved are actually no different from Redux. In fact, even Redux uses the React Context API at the bottom of its public API. However, it is only recently that the Context API has reached a sufficiently mature level.

Use Redux to create the React application

As mentioned above, the goal of this article is to show you how the new Context API can replace Redux in small applications. So, you’ll first create a simple React app using Redux. Then, you’ll learn how to remove the state management library to make better use of the React Context API.

The example application you will build is a list that deals with some popular foods and their sources. The app will also include a search function that allows users to filter lists by keywords.

Eventually, you’ll create an application similar to the one described below:

Project requirement

Since this article uses only React and some NPM libraries, you don’t need anything other than Node.js and NPM. If you haven’t already installed Node.js and NPM, download and install them from the official website.

After installing these dependencies, you’ll also need to install the create-react-app tool. This tool helps developers create React projects. Open a terminal and run the following command to install:

npm i -g create-react-app
Copy the code

Setting up the React application

After create-react-app is installed, go to the project directory and run the following command:

create-react-app redux-vs-context
Copy the code

After a few seconds, create-React-app will complete the creation of the application. After that, go to the new directory created by the tool and install Redux:

Go to the application directory
cd redux-vs-context

# installation Redux
npm i --save redux react-redux
Copy the code

Note: Redux is the primary library and react-redux is the library that facilitates interaction between React and Redux. In short, the latter acts as a proxy between React and Redux.

Use Redux to develop React applications

You’ve set up your React app, installed Redux, and now open your project in your favorite developer. Then create three files in the SRC folder:

  • foods.json: This file contains a static array to hold information about foods and their origins
  • reducers.js: This file is used to manage Redux status in the application
  • actions.js: This file is used to save the methods that trigger Redux state changes in the application

So, first, open the foods.json file and add the following:

[{"name": "Chinese Rice"."origin": "China"."continent": "Asia"
  },
  {
    "name": "Amala"."origin": "Nigeria"."continent": "Africa"
  },
  {
    "name": "Banku"."origin": "Ghana"."continent": "Africa"
  },
  {
    "name": "Pão de Queijo"."origin": "Brazil"."continent": "South America"
  },
  {
    "name": "Ewa Agoyin"."origin": "Nigeria"."continent": "Africa"}]Copy the code

As you can see, the data stored in files is nothing special. It’s just an array of different foods from different countries.

With the foods.json file defined, you can focus on creating your Redux Store. As a reminder, the Store is the only source of your app’s true state. Open your reducers.js file and add the following code:

import Food from './foods';

const initialState = {
  food: Food,
  searchTerm: ' '};export default function reducer(state = initialState, action) {
  // By action type
  switch (action.type) {
    case 'SEARCH_INPUT_CHANGED':
      const {searchTerm} = action.payload;
      return {
        ...state,
        searchTerm: searchTerm,
        food: searchTerm ? Food.filter(
          (food) = > (food.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > - 1)
        ) : Food,
      };
    default:
      returnstate; }}Copy the code

In the code above, you can see that the Reducer method receives two parameters: state and action. When you start your React application, the method will get the initialState it defined previously, and when you dispatch an instance of an action, the method will get the current state (no longer the initialState). Then, based on the contents of these actions, the Reducer method will generate a new state for your application.

Next, you need to define what these actions do. In fact, for the sake of simplicity, you’ll define a single action that will be triggered when a user enters a search term into your application. So, open the actions.js file and insert the following code:

function searchTermChanged(searchTerm) {
  return {
    type: 'SEARCH_INPUT_CHANGED'.payload: {searchTerm},
  };
}

export default {
  searchTermChanged,
};
Copy the code

Once the action is created, the next thing you need to do is wrap your App components into the Provider component provided by the React-Redux. The Provider transfers data (store) of the React application.

To use a provider, you will first create a store using initialState defined in reducers.js. Then, through the Provider component, you pass the Store to your App. To do this, you must open the index.js file and replace its contents with:

import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import reducers from './reducers';
import App from './App';

// Use the reducers information to create a store.
// This is because Reducers is the control center of Redux Store.
const store = createStore(reducers);

ReactDOM.render(
  <Provider store={store}>
    <App/>
  </Provider>.document.getElementById('root'));Copy the code

That’s it! You’ve just configured Redux in the React application. Now, you must implement the UI (user interface) so that your users can use the functionality implemented in this section.

Creating the React interface

Now that you’ve completed the core code in your application, you can focus on building your user interface. To do this, open your app.js file and replace its contents with the following code:


import React from 'react';
import {connect} from 'react-redux';
import actions from './actions';
import './App.css';

function App({food, searchTerm, searchTermChanged}) {
  return (
    <div>
      <div className="search">
        <input
          type="text"
          name="search"
          placeholder="Search"
          value={searchTerm}
          onChange={e= > searchTermChanged(e.target.value)}
        />
      </div>
      <table>
        <thead>
        <tr>
          <th>Name</th>
          <th>Origin</th>
          <th>Continent</th>
        </tr>
        </thead>
        <tbody>
        {food.map(theFood => (
          <tr key={theFood.name}>
            <td>{theFood.name}</td>
            <td>{theFood.origin}</td>
            <td>{theFood.continent}</td>
          </tr>
        ))}
        </tbody>
      </table>
    </div>
  );
}

export default connect(store => store, actions)(App);

Copy the code

For those of you who have not used Redux, the only thing unfamiliar is the Connect method used to encapsulate App components. This method is essentially a high-level component (HOC) that acts as the glue between the application and Redux.

Use the following command to launch your app and you will be able to access your app in your browser:


npm run start

Copy the code

However, as you can see, the app is pretty ugly right now. So, to make it look better, you can open the app.css file and replace its contents with the following:


table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 15px;
  line-height: 25px;
}

th {
  background-color: #eee;
}

td.th {
  text-align: center;
}

td:first-child {
  text-align: left;
}

input {
  min-width: 300px;
  border: 1px solid # 999;
  border-radius: 2px;
  line-height: 25px;
}

Copy the code

Done! Now that you have a basic React and Redux application, you can start learning how to migrate to the Context API.

Use the React Context API to implement the application

In this section, you will learn how to migrate your Redux application to the React Context API.

Fortunately, you don’t need to do a lot of refactoring between Redux and the Context API.

First, you must remove the Redux component from your application. To do this, open the terminal and delete the redux and React-Redux libraries:


npm rm redux react-redux

Copy the code

After that, references to these libraries are removed from the application. Open app.js and delete the following lines:


import {connect} from 'react-redux';
import actions from './actions';

Copy the code

Then, in the same file, replace the last line (the line starting with export Default) with the following:


export default App;

Copy the code

With these changes, you can rewrite your application using the Context API.

Migrate from Redux to the React Context API

To convert a previous application from a Redux-driven application to use the Context API, you need a Context to Store the application’s data (this Context will replace the Redux Store). In addition, you need a context. Provider component that contains the state, props, and the normal React component lifecycle.

To do this, you need to create a providers.js file in the SRC directory and add the following code to it:


import React from 'react';
import Food from './foods';

const DEFAULT_STATE = { allFood: Food, searchTerm: ' ' };

export const ThemeContext = React.createContext(DEFAULT_STATE);

export default class Provider extends React.Component {
  state = DEFAULT_STATE;
  searchTermChanged = searchTerm= > {
    this.setState({searchTerm});
  };

  render() {
    return (
      <ThemeContext.Provider value={{
        . this.state.searchTermChanged: this.searchTermChanged,
      }}> {this.props.children} </ThemeContext.Provider>); }}Copy the code

The Provider class defined in the above code is responsible for encapsulating other components in Themecontext.provider. By doing so, you can give these components access to state in the application and the searchTermChanged method that changes state.

To use these values in the component tree, you need to create a themecontext.consumer component. This component will need a Render render method that takes the props value as an argument.

So, next, you need to create a file called consumer.js in the SRC directory and write the following code to it:


import React from 'react';
import {ThemeContext} from './providers';

export default class Consumer extends React.Component {
  render() {
    const {children} = this.props;

    return (
      <ThemeContext.Consumer>
        {({allFood, searchTerm, searchTermChanged}) => {
          const food = searchTerm
            ? allFood.filter(
              food =>
                food.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1
            )
            : allFood;

          return React.Children.map(children, child =>
            React.cloneElement(child, {
              food,
              searchTerm,
              searchTermChanged,
            })
          );
        }}
      </ThemeContext.Consumer>); }}Copy the code

Now, to complete the migration, you’ll open the index.js file and wrap the App component with the Consumer component in the Render () function. In addition, you need to wrap the Consumer in the Provider component. The code looks like this:


import React from 'react';
import ReactDOM from 'react-dom';
import Provider from './providers';
import Consumer from './consumer';
import App from './App';

ReactDOM.render(
  <Provider>
    <Consumer>
      <App />
    </Consumer>
  </Provider>.document.getElementById('root'));Copy the code

Knock it off! You just finished migrating the React Context API from Redux. If you launch your application now, you’ll find that the entire application works as usual. The only difference is that your application no longer uses Redux.

“The new React Context API is a great alternative to Redux in terms of reducing the size of your application.”

Off topic: Use Auth0 to make your React app more secure

There is a detailed tutorial on how to use Auth0, but the translator feels that this is not relevant to the topic of this article, so it is not translated. Those who are interested can read this section in the original text.

conclusion

Redux is an advanced state management library suitable for building large-scale React applications. On the other hand, the Context API can be used in small-scale React applications with byte size data changes. By using the Context API, you don’t have to write a lot of code like reducers, Actions, etc., to do the logical presentation through state changes.