React Context API for Beginners (Using Context Hooks)

As a ReactJs developer, you may have encountered some problems when using traditional state management methods (ie: usestate hooks), and got frustrated with drilling props from one component to another, this is your React reference for you. This is the perfect opportunity to get acquainted with API using the UseContext hook.

In this tutorial, we will learn about using ReactContext API to build a Counter demo app.

If you are just getting started with ReactJs framework, it would be advisable for you to have knowledge of React usestate hooks and props drilling before proceeding with this tutorial.

Feel free to check the official documentation of Reactjs.

Problem (Props Drilling)

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

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

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 above code snippet, our state is being transferred from the parent component to the child component and vice versa.

Therefore, this method of state management may not be suitable for large projects with a very complex structure, which is where the ReactContext API comes to our rescue.

What is ReactContext API?

The ReactContext API is a way to manage app state globally. It can be used with a usestate hook to share state between deeply nested components, compared to usestate alone. It was also introduced to solve the problem of passing props from one component to another (props drilling).

common use cases

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

  • app theme
  • user settings
  • certification state
  • Preferred Language
  • Component positioning with dynamic children in components like tabs, steppers etc.

Now, let’s move on to see the problem solved by the ReactContext API.

In this example, we will be building a counter demo app with respect to the Reactjs useContext hook.

let’s get started

Ok, let’s create a new react-app using the command “npx create-react-app app-name” in terminal. Then, navigate 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 the boilerplate of the Counter app that we are about to build using the ReactContext 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:

Ok, now that we are done with the stable part of the counter app, let’s add increment and decrement functionality to the app using the ReactContext API.

creating a response context

To create a context for our Counter app, we need 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 first need to 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 initializing createContext, it’s time to create our counterprovider function, this is where all of our global states and functions will be declared and initialized. It is only used to encapsulate components that require 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 a usestate hook called “counter”, where the counter stores the number of counts, and the “increment” and “decrement” functions to decide which values ​​are raised respectively. or goes down or not.

Now, let’s provide context to the child components. To do this, we need 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

OK, now that we’ve made our global state available to the component, it’s time to access our state via the useContext hook in our App.js file.

To do this, we need 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 destroy our global states with the useContext hook.

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

exit fullscreen mode

Finally, we are ready to pass our function to our button’s onclick event props to increment and decrement 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

Having done that, it’s time to test our app to see if it’s working.

picture description

Congratulations, there you have it, a counter app that uses the useContext hook with the help of the ReactContext API.

conclusion

Glad you got it to this point. Throughout this tutorial, you learned how to build a Counter app using the ReactContext API. We started with the introduction of the ReactContext API and then explored it using the UseContext hook provided to us by ReactJs as an inbuilt state management package. Feel free to learn about Reactjs and its libraries from official documentation and gain more knowledge using React Context API.

Leave a Comment