Using React Context with Functional Components

Dan Fyfe
3 min readNov 12, 2019

--

Photo by Markus Spiske on Unsplash

Are you sick of prop drilling? Does redux make your brain hurt? Lucky for you, there’s React Context!

Context is a way to share data with multiple components and their descendants without having to pass them down through each layer of the component tree.

Say you have a piece of an app that displays a set of ‘things’ as a list and also as a graph in a different section. Component-wise, we might end up with something like this:

InfoContainer   - ListContainer
- ListDisplay
- ListItem
- GraphContainer
- GraphDisplay

We have a parent component, InfoContainer, which has two children, ListContainer and GraphContainer, which each have their own components for displaying. We will need to get the same set of ‘things’ from InfoContainer down to the Display components. Just pass it through each component! Not a big deal, right? Since this is a simple example, it may seem silly not to, but just imagine if you had a lot more going on and more components needed access to the same data. It can get real messy, real fast.

Let’s use Context! First lets make a file called thingsContext.js and fill it like so:

import React from 'react'const ThingsContext = React.createContext({})export const ThingsProvider = ThingsContext.Providerexport default ThingsContext

We are doing a few things here: Creating the context ( I put an empty object as an argument, which will be filled later ), then creating a way to ‘provide’ the context to components as ThingsProvider. We will be accessing the context with the useContext Hook later.

Our InfoContainer component would look something like this:

import React from 'react'
import ListContainer from './ListContainer'
import GraphContainer from './GraphContainer'
import { ThingsProvider } from '../thingsContext'
const InfoContainer = props => { // pretend we are fetching these 'things'
const things = [
{id: 1, name: 'thing 1', length: 5},
{id: 2, name: 'thing 2', length: 2},
{id: 3, name: 'thing 3', length: 6},
{id: 4, name: 'thing 4', length: 10},
{id: 5, name: 'thing 5', length: 1}
]
return(
<div>
<ThingsProvider value={things}>
<ListContainer/>
<GraphContainer/>
</ThingsProvider>
</div>
)
}
export default InfoContainer

Pretty simple. All we have done is made an InfoContainer component that contains a ListContainer and a GraphContainer. We then wrapped both of those components together in our ThingsProvider and passed in our ‘things’ as the value property. This will give any child, grandchild, etc. of the components access to our ‘things’.

Next we can access our context. Our ListContainer will contain another component called ListDisplay that we will use to display the ‘things’ as a list. It should look something like this:

import React, { useContext } from 'react'
import ThingsContext from '../thingsContext'
import ListItem from '../components/ListItem'
const ListDisplay = props => { const things = useContext(ThingsContext) const renderThings = things => {
return things.map( thing => {
return <ListItem key={thing.id} thing={thing}/>
})
}
return(
<ul>
{renderThings(things)}
</ul>
)
}
export default ListDisplay

The important part here is the useContext Hook. We import our ThingsContext and pass it into our useContext Hook, save it as a variable and thats it! We have access to the data we need and that data can also be accessed by other components. We also skipped right over the ListContainer component altogether and didn’t have to pass anything down! Very cool, very handy.

Like everything, there is a little more to this, but this should get you started. There is a different approach when using Class components too, which was not covered here, but you can check out in the link below. Thanks for reading!

Helpful Links

--

--