Context in React

Pritpal Singh - Sep 15 - - Dev Community

The Problem with Passing Props

In React, passing data through props can become cumbersome as your app grows. For example, if you need to pass data to deeply nested components, you have to pass the data through every intermediary component. This can lead to “prop drilling,” where you’re passing the same data through multiple layers of components.

Diagram Showing Props Drilling

This is where the Context API comes in. With Context API, you can store data at the top level of the component tree and make it available to all other components that need it without passing props.

The React Context API is a way to manage and share state across your application without having to pass props down through every level of your component tree. It helps manage global data that needs to be accessible by many components at different nesting levels.

Diagram Showing Use of Context API


Get Started with the Context API

It's a good practice to organize your React application by creating a separate folder for context files.

  • Create a Context Object

Create a context object using the createContext function from the 'react' library. This context object will hold the data that you want to share across your application.

userContext.js

import React from "react";

const UserContext = React.createContext();

export default UserContext;
Enter fullscreen mode Exit fullscreen mode
  • Wrap Components with a Provider

Once you create a context object, you use its Provider component to wrap the components that need access to the shared data. For example, if you create a UserContext, you would wrap your components inside the <UserContext.Provider>. This allows any component within that wrapper to access the shared data provided by the context.

It's important to note that the Provider component should be wrapped around the top-level component in an application to ensure that all child components have access to the shared data.

userContextProvider.jsx

import React from 'react'
import  UserContext from "./userContext";

const userContextProvider = ({children}) => {
    const [user, setUser] = React.useState(null);
  return (
    <UserContext.Provider value={{user, setUser}}>
        {children}
    </UserContext.Provider>
  )
}

export default userContextProvider
Enter fullscreen mode Exit fullscreen mode

app.jsx

import React from 'react'
import UserContextProvider from './context/userContextProvider'
import Login from './components/Login'
import Profile from './components/Profile'

function App() {

  return (
    <>
      <UserContextProvider>
      <Login/>
      <Profile/>
      </UserContextProvider>
    </>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode
  • useContext()

useContext() in React to access the data from a context that was provided by a Context.Provider. This hook allows any component inside the provider to easily "consume" or use the shared data without needing to pass it down through props.

  • Writing Data

When we share data through context, we pass both reading and updating functions, like in the earlier example where we passed an array with user (for reading) and setUser (for writing or updating the data).

In real applications, we often use context to share multiple pieces of data, not just two. Depending on the functionality, you'll have different contexts for different purposes, like:

  • A UserContext for managing user data (login, profile, etc.).
  • A ThemeContext for handling themes (dark mode, light mode).
  • An AuthContext for authentication states (logged in, logged out).

Each context can have its own file for organization, making it easier to manage and maintain the shared data for different parts of the app.

Login.jsx

import React from 'react'
import UserContext from '../context/userContext';


function Login() {
    const [username, setUsername] = React.useState("");
    const [password, setPassword] = React.useState("");

    const {setUser} = React.useContext(UserContext);

    const handleSubmit = (e) => {
      e.preventDefault() //this prevent the data sending through post method to random location on clicking button
      setUser({username, password}); //setUser for writing data.
    };
  return (
    <div>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="Username"
      />
      <input
        type="text"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button onClick={handleSubmit}>Login</button>
    </div>
  );
}

export default Login
Enter fullscreen mode Exit fullscreen mode
  • Reading Data

Profile.jsx

import React from 'react'
import UserContext from '../context/userContext';

function Profile() {

  const { user } = React.useContext(UserContext);

  if (!user) return <div>Please Login.</div>

  return (
    <div>
        Welcome User: {user.username}
    </div>
  );
}

export default Profile
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . .
Terabox Video Player