DEV Community

Cover image for React Context API for Beginners (using useContext hook)
Samuel Adex
Samuel Adex

Posted on

React Context API for Beginners (using useContext hook)

As a Reactjs Developer, you must have encountered some problems while using traditional state management methods (i.e: useState hook), and have been frustrated by props drilling from one component to another, this is the perfect opportunity for you to be introduced to React Context API using useContext hook.

In this tutorial, we’ll dive into the use of React Context API to build a Counter Demo App.

If you’re just starting out with Reactjs Framework, it will be advisable for you to have a knowledge of React useState hook and Props drilling before going ahead with this tutorial.

Feel free to check out Reactjs official documentation.

The Problem (Props Drilling)

As a Reactjs developer, we all know that Reactjs makes use of components where props are passed from parent component to child component. This is the general principle of Reactjs Component-based single-directional flow of data. But as your application grows, this may not be the ideal method to manage a state or certain global properties that a large number of components may require.

Before moving further, let’s take a look at an example of props drilling.

import { useState } from "react";
import ReactDOM from "react-dom/client";

function Component1() {   
      const [user, setUser] = useState("Jesse Hall");   

      return (
            <>
               <h1>{`Hello ${user}!`}</h1>         
              <Component2 user={user} />      
          </>   
      );
}

function Component2({ user }) {   
      return (
            <>
                 <h1>Component 2</h1>
                 <Component3 user={user} />      
            </>   
       );
}

function Component3({ user }) {   
      return (
            <>
                 <h1>Component 3</h1>
                 <Component4 user={user} />
            </>
      );
}

function Component4({ user }) {   
      return (      
            <>         
                  <h1>Component 4</h1>         
                  <Component5 user={user} />      
            </>  
       );
}

function Component5({ user }) {   
      return (
            <> 
                  <h1>Component 5</h1>
                  <h2>{`Hello ${user} again!`}</h2>      
            </>   
      );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Component1 />);

Enter fullscreen mode Exit fullscreen mode

As you can see in the code snippet above, our state is being passed down from the parent component to the child component and vice-versa.

Therefore, this method of state management might not be suitable for larger projects that have a very complicated structure, that’s where the React Context API comes to our rescue.

What is React Context API?

React Context API is a way to manage an App state globally. It can be used together with the useState hook to share state between deeply nested components more easily than with useState alone. It was also introduced to solve the problem of passing down props from one component to another (props drilling).

Common Use Cases

In general, Context API should be used primarily for non-frequent updates such as:

  • App Theme
  • User Settings
  • Authentication State
  • Preferred language
  • Component state with dynamic children in components like Tabs, Steppers, etc.

Now, let’s go ahead to see the problem solved by React Context API.

In this example, we’ll be building a Counter Demo App in relation to the Reactjs useContext hooks.

Let’s Get Started

Okay, let’s create a new react-app using “npx create-react-app app-name” command in the Terminal. Then, go to our App.js file in the “src” directory and write the following jsx code for the Counter Demo App UI.

import React from 'react';

function App() {   
      return (      
          <div className="container">         
                <h1>Counter App</h1>
                <div className="count-wrapper">
                      <button>+</button>
                      <span>0</span>
                      <button>-</button>         
                </div>      
        </div>   
    );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

As you can see in the code above, we only have a boilerplate of the Counter App we’re about to build using React Context API. Now, let’s add our CSS code to the index.css file.

*{
  margin:0;
  padding: 0;
  box-sizing: border-box;
}
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;  
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

.container{
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.container h1{
  font-size: 40px;
  margin-bottom: 12px;
}
.container .count-wrapper{
  display: flex;
  align-items: center;
  gap: 20px;
}
.container .count-wrapper button{
  border: 1px solid grey;
  background: transparent;
  padding: 10px 15px;
  font-size: 20px;
  font-weight: bold;
  cursor: pointer;
}
.container .count-wrapper span{
  font-size: 25px;
  font-weight: bold;
}

Enter fullscreen mode Exit fullscreen mode

After running our React app, we should have something like this in our browser:

Image description

Alright, now we’re done with the static part of the Counter App, let’s add the Increment and Decrement functionality to the App using React Context API.

Creating a React Context

To create a context for our Counter App, we have to create a counterContext.js file in the src directory, this is where the Context API will be initialized and all our global states will be stored.

To do this, we must first import “ createContext” from React and initialize it in the counterContext.js file.

import { useState, createContext } from 'react';
const counterContext = createContext();

Enter fullscreen mode Exit fullscreen mode

After createContext has been initialized, it’s time to create our CounterProvider function, this is where all our global states and functions will be declared and initialized. It is also used to encapsulate only the components that need the state in this context.

import { useState, createContext } from 'react';

const counterContext = createContext();

//Contex Provider used to encapsulate only the components that needs the state in this context
export const CounterProvider = ({children})=>{

    const [counter, setCounter] = useState(0);

    //Increase counter
    const increment = () => {
        return setCounter(counter + 1);
    }

    //Decrease counter
    const decrement = () => {
        return setCounter(counter - 1);
    }


    return (
        <counterContext.Provider value={{counter, increment, decrement}}>
            {children}
        </counterContext.Provider>
    )
}

export default counterContext;

Enter fullscreen mode Exit fullscreen mode

In the above code snippet, our CounterProvider has three declarations; two functions called “increment” and “decrement”, and one useState hook called “counter”, where the counter stores the number of counts, and the “increment” and “decrement” function decides if the value goes up or down respectively.

Now, let’s provide the context to the child components. To do this, we’ll have to wrap the App component with the CounterProvider Provider in our index.js file.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import {CounterProvider} from './counterContext'


ReactDOM.render(
  <React.StrictMode>
    <CounterProvider>
      <App />
    </CounterProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

Enter fullscreen mode Exit fullscreen mode

Alright, now we’ve made our global state available to the component in need of it, it is time to make use of our state through the useContext hook in our App.js file.

In order to do this, we’ll have to import the useContext hook from React.

import React, {useContext} from 'react';
Enter fullscreen mode Exit fullscreen mode

Then, we also need to import our counter context from the counterContext.js file.

import counterContext from './counterContext';
Enter fullscreen mode Exit fullscreen mode

Now let’s destruct our global states from the useContext hook.

const {counter, increment, decrement} = useContext(counterContext);
Enter fullscreen mode Exit fullscreen mode

Finally, we are ready to pass our function to the onClick event props of our button in order to increase and decrease the counter.

import React, {useContext} from 'react';
import counterContext from './counterContext';

function App() {
  const {counter, increment, decrement} = useContext(counterContext)

  return (
    <div className="container">
      <h1>Counter App</h1>
      <div className="count-wrapper">
        <button onClick={increment}>+</button>
        <span>{counter}</span>
        <button onClick={decrement}>-</button>        
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

After this has been done, now is time to test our App to see if it is working.

Image description

Congratulations, here you have it, A Counter App with the help of React Context API using the useContext hook.

Conclusion

Glad you made it to this point. Throughout this tutorial, you’ve learned how to build a counter App using React Context API. We started with an introduction to React Context API and then explored it using the useContext hook provided to us by Reactjs as an inbuilt state management package. Feel free to learn more about Reactjs and it’s libraries from the official documentation and gain more knowledge using React Context API.

Top comments (0)