Simplifying Data Sharing in React: An Introduction to the Context API

Simplifying Data Sharing in React: An Introduction to the Context API

A Beginner's Guide to the React Context API and Its Practical Applications

ยท

6 min read

One of the features that make React powerful is its ability to manage and share states between components. The Context API is a way to share state between components without having to pass props down through multiple levels of the component tree. In this blog post, we'll explore what the Context API is, how it works, and how to use it in a React application.

The Context API consists of two main parts: the Provider and the Consumer. The Provider is a component that wraps around other components and provides the state. The Consumer is a component that can access the state provided by the Provider.

How to Use Context API

There are three stages involved in using context API in react

  1. Creating the context

  2. Providing the context

  3. Consuming the context

Stage 1: Creating the Context

To use the Context API, you first need to create a context using the createContext function. This function takes an optional default value as an argument. Here's an example of how to create a context for a user's name:

const UserContext = React.createContext();

Stage 2: Providing the Context

Once you have created a context, you can use it to provide a state to your components. To do this, you need to wrap the components that will provide the state in a Provider component. The Provider component takes a value prop, which is the state that you want to share. Here's an example of how to use the UserContext Provider to provide a user's name:

<UserContext.Provider value={user.name}>
  <App />
</UserContext.Provider>

Stage 3: Consuming the Context

There are two ways to consume a context:

  1. Using the consumer component

  2. Using the useContext() hook

The Consumer Component

Once you have provided the state, you can access it using the Consumer component. The Consumer component takes a function as a child, which is called with the value provided by the Provider. Here's an illustration of how to use the UserContext Consumer to display a user's name:

<UserContext.Consumer>
  {userName => <p>Welcome, {userName}</p>}
</UserContext.Consumer>

The Consumer component can be used inside any component that needs to access the state provided by the Provider. This way, you don't need to pass props down through multiple levels of the component tree just to share state between components.

The useContext() Hook

The useContext hook is a React hook that lets you read and subscribe to context from your component. The useContext hook accepts a context object( the value returned from the createContext( )). It is determined as the value passed to the closest Context.Provider

import { useContext } from 'react'

function myComponent() {
const userName = useContext(context);
return <p>Welcome, {userName}</p>
}

The Context API also makes it easy to update the state. To do this, you simply need to update the value prop of the Provider component. All the components that are using the Consumer component will automatically re-render with the new state.

Practical Applications of Context API

  1. Managing Global state

  2. Simplifying Data Flow

  3. Improving Code Reusability

  4. Dynamic Themeing

  5. Language Localization

  6. Managing User Authentication and Authorization

  7. Accessing Third-Party APIs

  8. Storing and Managing Form Data

  9. Managing Loading States

  10. Managing Error States

Let's look at one of the practical applications above to get a better view of context API

Dynamic Themeing

The Context API can be used to store and manage the theme of an application, allowing for easy switching between themes.

To begin, let's start by setting up a quick react app by typing this command in your terminal: npx create-react-app context, then we should create a component folder and inside our component folder, we should create a themeContext component.

The structure of our react project should look like this:

First of all, we will create our ThemeContext which we will use in our application. we will then declare a isDarkTheme variable and set it to false by default. Then we will declare a toggleTheme function to switch the value of the isDarkTheme. The application's theme-related functionality will be controlled by this state since it determines how all associated CSS is added or removed.

import React, { createContext, useState } from "react"

export const ThemeContext = createContext({
    isDarkTheme: false,
    toggleTheme: () => {},
})


const ThemeProvider = ({ children }) => {
    const [isDarkTheme, setIsDarkTheme] = useState(false);

    const toggleTheme = () => {
        setIsDarkTheme(!isDarkTheme)
    }
  return (
    <ThemeContext.Provider value={{ isDarkTheme, toggleTheme }}>
            {children}
        </ThemeContext.Provider>
  )
}

export default ThemeProvider

To use our isDarkTheme variable and toggleTheme function, we need to first wrap our App component in the index.js file with the ThemeProvider component

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import ThemeProvider from "./components/ThemeContext"
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ThemeProvider>
            <App />
        </ThemeProvider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Now we bring in the useContext hook, and pass in the ThemeContext as an argument to the hook to consume our global state variables in our App.js components

import React, { useContext } from "react"
import "./App.css"

import { ThemeContext } from "./components/ThemeContext"

const App = () => {
    const { isDarkTheme, toggleTheme } = useContext(ThemeContext)

    return (
        <div className={`app ${isDarkTheme === true ? "dark" : ""}`}>
            <button
                className={`button ${isDarkTheme === true ? "dark" : ""}`}
                onClick={toggleTheme.bind(null)}>{`Switch to ${
                isDarkTheme === true ? "Light Theme" : "Dark Theme"
            }`}</button>
        </div>
    )
}

export default App

To conclude our small app, we need to include our styles for light and dark modes. When we set isDarkMode to true, dark-mode CSS will replace the default values and the light theme will be loaded by default.

:root {
    --bg-light: #f4f4f4;
    --bg-dark: #232323;
    --text-light: var(--bg-dark);
    --text-dark: var(--bg-light);
    --transition: 0.3s;
}
* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    transition: all var(--transition);
}
.app {
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-light);
}
.app.dark {
    background: var(--bg-dark);
}
.button {
    padding: 1rem;
    border: none;
    border-radius: 0.3rem;
    min-width: 15rem;
    font-size: 1rem;
    cursor: pointer;
    background: var(--bg-dark);
    color: var(--text-dark);
    border: 1px solid var(--bg-dark);
}
.button.dark {
    background: var(--bg-light);
    color: var(--text-light);
}

Then the final result of our small application will be:

Conclusion

The Context API is a great way to share state between components without having to pass props down through multiple levels of the component tree. It's a powerful feature that makes it easy to manage and share state in a large React application.

One of the biggest advantages of Context API over other state management libraries such as redux is that it's a simpler and less complex way to manage state. It's typically used for state that is not specific to one component but is needed by multiple components in the application. The Context API is also a great option when you don't need all the features that redux provides, such as middleware and time-travel debugging.

If you enjoyed this article and found it interesting, make sure to drop a comment and thumb up. See you next time โœŒ๐Ÿฟ.

ย