React new Context API

What is it about ?

The Context API is a component structure provided by the React framework, which enables us to share specific forms of data across all levels of the application. It’s aimed at solving the problem of Prop drilling.
Prop drilling (also called “threading”) refers to the process you have to go through to get data to parts of the React Component tree.
Before the Context API, we could use a module to solve this, which led to the increasing popularity of state management libraries like Redux. Libraries like Redux allows you to get data from the store easily, anywhere in the tree. However, let’s focus on the Context API.

Why ?

As with most component-based frontend frameworks, passing some form of data from one component to another is usually a real need. Typically it comes in the form of passing data from a parent to a child component or even child to parent components. This leads to components having data they don’t actually need, but they need to pass on down the tree.

This gets cumbersome pretty fast especially for certain types of props (e.g locale preference, UI themes, language settings etc) that are required by many different components within an application. The Context API aims to solve this problem, and provides a way to share data values like this between components without having to pass a prop through every level of the app tree.

Is it New ?

The Context API has actually always been there but was considered experimental. Moving forward the API was improved to stability, and as of the release of version 16.3, the feature was made available and subsequently considered a new addition to the clan of features that make React a wonderful framework.

Before now many of the tools, we have been used to, like react-redux, react-native-flux, MobX-react, and react-router all used context to function, so you were probably already using and loving it, even if not directly.

How to use it ?

1. React version >= 16.3

2. Import it from React

3. Follow the steps below

1. Create the Context

First, we need to create the context, which we can later use to create providers and consumers

 
import React from 'react'


// This is the equivalent to the createStore method of Redux
// We can create it in a separate file or in a sharered file with a component
// As long as we can export it


const MyContext = React.createContext()

export default MyContext

2. Create the Provider

Once that’s done, we can import the context and use it to create our provider.
 

In it, we initialize a state with some values, which you can share via value prop our provider component

 
 
    
import React, { Component } from 'react'
import appContext from 'utils/appContext'
const { Provider } = appContext

export default class AppState extends Component {
  state = { number: 1 } // Inital state like Redux

  mutNumber = () => {
    this.setState({
      ...this.state,
      number: this.state.number + 1,
    })
  }

  render() {
    return (
      <Provider
        value={{
          state: this.state,
          actions: {
            mutNumber: this.mutNumber,
          },
        }}
      >
        {this.props.children}
      </Provider>
    )
  }
}

3. Wrap our App with it

To make the provider accessible to other components, we need to wrap our app with it, just like in Redux

 
 
import React from 'react'
import { render } from 'react-dom'
import AppState from './state'
import App from './App'

render(
  <AppState>
    <App />
  </AppState>,
  document.getElementById('root')
)

4. Create the Consumer

 

We’ll need to import the context again and wrap our component with it which injects the context argument in the component. Afterward, it’s pretty straight forward. You use context, the same way you would use props. It holds all the values we’ve shared in MyProducer, we just need to use it

 
 
import React, { Component } from 'react'
import appContext from 'utils/appContext'
const { Consumer } = appContext

export default class MyChildComponent extends Component {

  render() {
    return (
       <Consumer>
         {({ state, actions }) => (
           <div>
             <span>{state.number}</span>
             <button onClick={actions.mutNumber}>+</button>
           </div>
         )}
       </Consumer>
    )
  }
}

5. Alternative, use hooks

 

Accepts a context object (the value returned from React.createContext) and returns the current context value for that context. The current context value is determined by the value prop of the nearest <MyContext.Provider> above the calling component in the tree.

 
 
import React from 'react'
import appContext from 'utils/appContext'

export default function MyChildComponent(props) {
  const value = React.useContext(appContext)
  const { state, actions } = value

  return (
	<div>
      <span>{state.number}</span>
      <button onClick={actions.mutNumber}>+</button>
    </div>
  )
}

6. Alternative, use static in classes

 

Leave the static propery as context type and access context in methods as using this.context

 
 
import React, { Component } from 'react'
import appContext from 'utils/appContext'

export default class MyChildComponent extends Component {
  static contextType = appContext

  render() {
	return (
	  <div>
      	<span>{this.context.state.number}</span>
      	<button onClick={this.context.actions.mutNumber}>+</button>
      </div>
	)
  }
}