DEV Community

Mandy Petrakis
Mandy Petrakis

Posted on

Context, Simply Put

When I started to learn React, I was overwhelmed by the concept of Context so I immediately forgot everything I read and decided I would just never use it. Then I had to drill state and setState 5+ components deep in a bootcamp project and I thought maybe I should give Context another chance. At that point I was more familiar with state and component trees and armed with that confidence (and a playlist of youTube videos) I set out to understand and implement Context in my app, and lets just say I nailed it. Here is my simplified explanation for anyone just starting out with Context.

What is Context?

Context is a way of accessing data through your whole component tree without having to pass props down manually at every level. Once Context is created you can import it in any component you wish to access the data. Simply put, its like creating a global state.

When to use Context?

I had read a few suggestions to use Context sparingly which was part of the reason I didn't spend time learning it initially, and frankly, I don't heed that advice now. For me, Context makes my code feel a lot cleaner and better managed. If I need access to a piece of state in 3 or more components, I'm using Context. That is especially true if I'm going update the state and I want the change to persist across all pages of my app. Common examples people use for Context are setting a dark theme and referencing if a user logged in. I personally use it often with data I have fetched from an API.

How to do it:

We will need to do two things to use Context:

  1. Establish Context with createContext and wrapping components that will use the context in a Context.Provider.

  2. Importing the context in the consumer component with useContext. (With a bonus method of importing Context at the end!)

First, decide where you want to store your context data. I like to put it in a separate Context component and import it to my App component. This keeps my code tidy but you can also establish Context directly in your App component. Like state, you just want to make sure it lives in a parent to all the components that will eventually import the data. If you are storing context in a Context component like me, you will need to pass it a {children} prop.

In the Context component import createContext from react with your other hooks. In this example, I'm going to useState to store the data we will pass as context to the consumer components.

Next we will need to use the createContext hook to declare our context outside our Context component using the createContext() function. We declare the context outside the Context component because we are going to export it for use in our consumer components.

Your code should look like this so far:

One

Now we need to tell React what data our DataContext we just created will hold. This is usually where I would useEffects to fetch data from an API and assign it to a state variable but to keep our example clean and simple I'm just going to declare the state with a default value of an array of numbers.

From here we create the 'provider component' for the DataContext as a return from our Context component. This DataContext.Provider component takes one prop called value which we assign data (our state from the previous step) and wraps around the {children} prop we gave to our Context component earlier. Like this:

Two

What if we wanted to use setData in another component of the app? Well, we could declare another context and call it something like UpdateDataContext and wrap both our child and DataContext.Provider in the UpdateDataContext.Provider. If this were unrelated data, I would probably go ahead and do that.

Instead since setData is part of our data state, in our DataContext.Provider we set our value to an array of [data, setData]. This will pass both our data and setData function to our children components in our single DataContext.Provider.

Three

The final step in our provider component process is to import our Context component to our App component and wrap it around all the children, or 'consumer components' we want to pass our data to.

Four

At this stage, our data and setData are available to all the components in our app without having to pass any props! Amazing, but how do we access them? Thats step 2...

useContext

Lets go directly to ComponentC, bypassing components A and B. Here we will import useContext from react as well as our DataContext from our Context component.

Five

We'll then take the useContext hook, pass it DataContext and declare the variables we will be setting the data to in ComponentC.

Six

Viola! You now have access to your data state and setData function in ComponenetC to use as you wish with out having to pass the prop through multiple components.

TLDR:

To recap, in order to create globally accessible state with Context in your app we:

Created the Context Provider by:

  1. Creating a Context component and passing it a prop of {children}.
  2. Importing createContext from react
  3. Declaring and exporting our DataContext from createContext() outside the Context component.
  4. Declaring the state we will use as our context data inside the Context component.
  5. Wrapping our {children} in the DataContext.Provider that has one prop of value and setting it to the state we declared in step 4.
  6. Exporting our Context component and importing it in the App component to wrap around all the components in our app.

Accessed the Context in our consumer component by:

  1. Importing useContext from react and DataContext from our Context component in our consumer component.
  2. Assigning our data and setData variables using useContext and passing it our DataContext.

Bonus!

The above works just fine but one more thing I like to do to streamline my code is rather than importing useContext in my consumer, I export a function that returns useContext() from my Context component so I only have to import this function to to access my data in my consumer components. This is what it looks like in both Context and ComponenetC.

Seven

What we did was:

  1. Import useContext in the Context component and remove it from ComponentC.
  2. Export the useData function that returns useContext(DataContext).
  3. Imported useData in ComponentC.

Thats it! After setting up Context once or twice I felt a lot more confident but I did reference my notes on future tries so write your own workflow or save this blog for future reference!

Top comments (4)

Collapse
 
jegangits profile image
jegan

I have one question. is this re-render the componentA and B while updating the value.

Collapse
 
mandy_petrakis profile image
Mandy Petrakis

Hi! Any component that uses the "data" state that we assigned to our context will re render if you assign a new array with the setData function.

Collapse
 
jegangits profile image
jegan

i am not sure. i have some doubt. if i update(setState) the value in componentC does it reRender the component A and B?

Thread Thread
 
dnelson35 profile image
DNelson35

If the state is updated inside the context component, it will cause a re-render on all the components that use the context and consume that state via the useContext hook. This is because, whenever the state inside the context changes, React will trigger a re-render on all the components that are subscribed to that context. However, components that do not use the context will not be affected by the state change and will not be re-rendered.