📕
WP SandBox
  • CMS SandBox
  • Introduction
    • What are frameworks?
    • What is a Content Management System (CMS)?
    • Framework vs Library — differences in web development
      • Library vs Framework
  • CMS or Frameworks?
  • How to Choose The Best CMS Platform
  • How To Install a WordPress Theme
  • Pages in WordPress: How to Create and Add a Page
  • What are the User Roles in WordPress?
  • How to add jQuery?
  • How to Use & Work with jQuery UI in Wordpress
  • React JS
    • What exactly is React?
    • React JS— Architecture
    • The Flux Architectural Pattern
  • React Context API
    • React Props/State
      • React 16.8
      • What is Context API?
Powered by GitBook
On this page
  • Using render props pattern
  • Using useContext hook

Was this helpful?

  1. React Context API
  2. React Props/State

What is Context API?

PreviousReact 16.8

Last updated 3 years ago

Was this helpful?

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

So If we have a parent component with child components inside it and each child component has further child components, then to pass data from the parent component to the innermost child component we have to pass it through all the parent components of the innermost child component. This is known asprop drilling.

This means even if any component is not using that prop, it has to receive that prop to pass it down to the child component. So to avoid this long chain of passing props through each level, we can use context API provided by React.

So using Context API, the innermost child can directly access the prop data sent from the parent component just like the connect method of react-redux library.

That’s enough for details. Let’s start with code to understand it better.

Clone the project repository from which is created in .

To run the application, execute the following commands in sequence

1. yarn install 2. yarn start

The JSX returned from src/components/HomePage.js looks like this

If you see, UsersList component accepts users and isLoading props and Filters component accepts handleSort and sortOrder prop.

If we have child components inside Filters or UsersList component which also needs these props, we have to pass them down from these components. So instead of passing those as props, we can access them using Context API.

You can find the initial source code .

There are 2 ways we can access the props passed from the context in React. Let’s start with the first approach.

Using render props pattern

Create a new context folder inside src folder and add UserContext.jsinside it with the following code:

import React from 'react';const UserContext = React.createContext();export default UserContext;

Here, we are creating a UserContext variable which we can use to access the data passed from the parent component

Now, in HomePage.js, import the UserContext we just created at the top

import UserContext from '../context/UserContext';

The React.createContext() function call returns an object with two properties, Consumer and Provider which we can access directly from UserContext variable as UserContext.Consumer and UserContext.Provideror using destructuring as follows

const { Consumer, Provider } = UserContext;

So now, change the JSX returned in HomePage component from this code:

<React.Fragment>
   <Header handleSearch={handleSearch} />
   <Filters handleSort={handleSort} sortOrder={sortOrder} />
   <UsersList users={users} isLoading={isLoading} />
</React.Fragment>

to this code:

<UserContext.Provider value={{ users, sortOrder, isLoading }}>
    <Header handleSearch={handleSearch} />
    <Filters handleSort={handleSort} />
    <UsersList />
</UserContext.Provider>

The Provider component accepts props inside value prop where we can pass all the props that we need to access in the components mentioned in between the opening and closing tag.

So now Header, Filters and UsersList component can directly access the props we have provided in value prop.

Now, to access the sortOrder prop inside Filters component, we need to change the returned JSX in Filters.js from this code:

<div className="sortBy">
    Sort by age
    <Select
      value={sortOrder}
      className="select-filter"
      onChange={handleSort}
      options={options}
    />
</div>

to this code:

<UserContext.Consumer>
    {(props) => (
      <div className="sortBy">
        Sort by age
        <Select
          value={props.sortOrder}
          className="select-filter"
          onChange={handleSort}
          options={options}
        />
      </div>
    )}
</UserContext.Consumer>

Here, In between the opening and closing tag of UserContext.Consumer, we provide a function for which the props we passed from HomePage.js will become automatically passed.

<UserContext.Provider value={{ users, sortOrder, isLoading }}>

So the props will contain all the props passed such as users, sortOrderand isLoading. We need only sortOrder prop in Filters.js so we can use destructuring here to further simplify it as:

<UserContext.Consumer>
    {({ sortOrder }) => (
      <div className="sortBy">
        Sort by age
        <Select
          value={sortOrder}
          className="select-filter"
          onChange={handleSort}
          options={options}
        />
      </div>
    )}
</UserContext.Consumer>

Now, we will access the isLoading and users prop inside UsersList component

Change UsersList component from this code:

const UsersList = ({ users, isLoading }) => {
  return (
    <div className="users-list">
      {isLoading ? (
        <p className="loading">Loading...</p>
      ) : (
        <React.Fragment>
          {users.map((user, index) => (
            <UserItem key={index} {...user} />
          ))}
        </React.Fragment>
      )}
    </div>
  );
};

to this code:

const UsersList = () => {
  return (
    <UserContext.Consumer>
      {({ isLoading, users }) => (
        <div className="users-list">
          {isLoading ? (
            <p className="loading">Loading...</p>
          ) : (
            <React.Fragment>
              {users.map((user, index) => (
                <UserItem key={index} {...user} />
              ))}
            </React.Fragment>
          )}
        </div>
      )}
    </UserContext.Consumer>
  );
};

Note, we have removed the props passed in the component and we are accessing it inside the UserContext.Consumer render prop.

So we are accessing the isLoading and users props passed from Context provider which are directly passed to the function defined in between the UserContext.Consumer.

The pattern of defining a function in between the opening and closing tag is known as render props pattern.

Using useContext hook

The React hooks API provides an easy way of accessing the passed props from consumer so there is no need of using render props pattern where we create a function to get the props values.

Just to recap, we pass the value prop to UserContext.Provider as

<UserContext.Provider value={{ users, sortOrder, isLoading }}>

Here, we are passing the object to the value prop with users, sortOrderand isLoading properties.

So we can access these object properties by using useContext hook as below

import { useContext } from 'react';
import UserContext from '../context/UserContext';const { users, sortOrder, isLoading } = useContext(UserContext);

Here, we have provided the UserContext we created in UserContext.js to useContext hook as a parameter

So to access sortOrder inside Filtes.js, we can just use

const { sortOrder } = useContext(UserContext);

and in UsersList.js, we can access the users and isLoading prop values as

const { users, isLoading } = useContext(UserContext);

Note: You can use the useContext hook to access props only in functional components and not in class based components. If you are using class based components, you have to use the render props pattern.

Conclusion:

React provides an easy way to avoid prop drilling using Context API. There are two ways to access the passed props. First is using render props pattern and second is using useContext hook.

Note that, we have just passed users, sortOrder and isLoading in the value prop. If you want you can even pass the handleSort and handleSearch handlers in the value prop. There is no problem in doing that. Also, If you have nested children like parent component contains child component and that child component contains another child component and the innermost child is using the state or props of parent component, then only you should use context otherwise you can just directly pass props.

Context just provides a better way to access props directly in the innermost child without the need of passing the props through each child to reach the innermost child.

You can find complete source code until this point

You can find complete source code for useContext hook functionality

HERE
HERE
HERE
this article
HERE