What is React Context?

React Context, introduced in React 16.3 release, is a stabilization of the Context API which is until now considered an experimental feature.

As mentioned in official ReactJS Docs

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

It is designed to share data that can be considered global for a React component tree. For examples, authenticated user, theme, preferred language etc.

Why use React Context?

  • Let’s answer this question;

    How do you pass the data from parent component to a child component nested in React Component Tree?

  • There are multiple answers to this question, it can be Redux or some third party state management libraries like MobX. But this will add complexity in an application and it’s not a viable decision to use them in every situation.
  • In typical React application, we use props to pass data from parent to child(in a top-down manner) in React component tree.
  • Passing props from parent to child is known as props drilling which is super cumbersome when we have a lot of components, among them some components do not require that props be passed down. This is shown in the following example;
    const App = () => <SuperParent />
          
    class SuperParent extends React.Component {
      state = {
        lastName: "lastName"
      }
      
      render() {
        return <Parent lastName={this.state.lastName} />
      }
    }
    
    const Parent = ({props}) =>  {
      return <Kid lastName={props.lastName} />    
    }
    
    const Kid = ({props}) => {
          return <p>{props.lastName}</p>
    }
    
  • React’s Context API is coming to solve this props drilling problem. Context provides a way to store the data like a global state and allows to access it in a required component without passing it down via props.

How React Context works?

There are three essential things in new Context API as following;

React.createContext

  • This will create a new Context object and will return an object with a Provider and Consumer
  • Its syntax is as follows;
    const MyContext = React.createContext(defaultValue);
    
  • The defaultValue argument is only used when a consumer component does not have a matching provider above it in the tree.
  • It does not make the consumer component to use defaultValue if we pass the undefined as a value in Provider component.

Context.Provider

  • Known as the Provider component, it is used higher in React component tree where we have our state.
  • It wraps components in the tree that will need access to context value.
  • It allows the consuming components to subscribe to the context Changes and will re-render whenever the Provider’s value prop changes.
  • It’s syntax is;
    <MyContext.Provider value={_value} />
    

Context.Consumer

  • This component is used anywhere below the provider in the React component tree. Multiple components can subscribe to one Provider component.
  • It uses the functions as child pattern and expects a function as its children prop which will receive the current context value and return a React node.
  • It’s syntax is;
    <MyContext.Consumer>
      {value => return value * 10}
    </MyContext.Consumer>
    
  • The value argument will be the same as the value prop of the closest Provider for this context above the tree. If no provider is available for this context above in the component tree then the value argument will be the same value as defaultValue passed while createContext

Usage of React Context

In the following code. we’ll refactor the above code using Context API;

So, first we’ll create a context;

const MyContext = React.createContext({})
export const MyContext_Provider = MyContext.Provider;
export const MyContext_Consumer = MyContext.Consumer;

Now, we’ll modify the SuperParent component to add the Provider in, as the SuperParent component is our top-level component and we have our state inside it.

//import
import { MyContext_Provider, MyContext_Consumer} from "./MyContext"


export class SuperParent extends React.Component {
  state = {
    lastName: "lastName"
  };

  render() {
    return (
      <MyContext_Provider value={this.state.lastName}>
        <Parent />
      </MyContext_Provider>
    );
  }
}

In the above case, we’re not passing the state to the Parent component using props. We wrap the Parent component in MyContext_Provider as it needs to access the lastName. Notice that the provider has a value prop. here, we can pass whatever state we like.


const Parent = () => {
  return <Child />;
};

const Kid = () => {
  return <MyContext_Consumer>{context => <p>{context}</p>}</MyContext_Consumer>;
};

here, we wrap the component inside MyContext_Consumer which actually needs access to the lastName property.

In the above example, we have wrapped the Parent component within MyContext_Provider as it contains the Child component which needs access to the lastName prop.

Will it replace Redux?

After releasing React 16.3, many people thought that the new Context API will kill redux but this claim is greatly exaggerated. A new Context API is not to replace Redux or other third party state management libraries but is another tool for React Developers which is specifically designed to solve the prop drilling problem.

It depends on the situation whether it requires the Context API or Redux. For example, a Context API is great and designed to passing down data to nested components from top to bottom. So, if you’re using Redux just to pass data from top-to-down then we can replace the Redux with new Context API. On contrast Context API doesn’t provide anything like Redux DevTools, adding centralized logic through Middleware. These things are required in large and complex applications where Context API can’t replace Redux totally.

So, the conclusion is Context doesn’t replace Redux. It’s another way to solve a problem and can be used in the appropriate situation.

Quick recap…

  • The new Context API is a re-work of existing Context API which is in experimental state until now.
  • The new context API is designed to pass data anywhere down to the component tree without having to pass it through all the way.
  • The new Context API solves the problem of prop drilling
  • There are 3 important pieces of the new Context API
    • React.createContext: A function that creates the context
    • Provider(Context.Provider): It is returned by createContext and accepts the value prop which can be whatever we want to pass through a component tree. This is very similar to the React-Redux’s Provider
    • Consumer (Context.Consumer): It is also returned by createContext and used to access the values from the context. It uses the render prop pattern. It works a bit like Redux’s connect function, taps into the data and make available to the component which uses it.
  • The new Context API is not a replacement of Redux but another tool to solve a problem if and when Redux brings complexity to the application.

References

ReactJS Documentation

Everything you need to know about React’s Context API

React’s New Context API Explained – Video

What is Prop Drilling?

Leave a Reply