How and When to use Context?

Understanding React “useContext” Hooks

Intro

Context is a react hook that allows you to pass data across any number of React components, regardless of nesting.

It allows you to access data globally without passing it as a prop. When the data provided by context changes, then only the components consuming the data re-render.

It does not say anything about "managing" values-it only refers to "passing" and "sharing" data. Context is a form of dependency injection. It is a transport mechanism—it doesn't "manage" anything. Any "state management" is done by you and your own code, typically via useState/useReducer.

For better understanding, in this article we will be implementing the cart feature mostly found in an e-commerce app.

How to use useContext?

Create context

  • It is created using the createContext()API.
  • While creating context, we can provide a default value, this value is applied when we are not providing a provider i.e the Component is out of the scope of the provider.
  • Context.Provider component available on the context instance is used to provide the context to its child components.
  • value prop provides the content of context to child components
//cart-context.js

import React, { createContext } from 'react'

export const CartContext = createContext('defaultValue') //creating a context

//This component will contain all functionalities that need to be at a global level.
export const CartProvider = ({ children }) => {
const [cartState, setCartState] = useState({})

  const value = {
    cartState,
    setCartState,
  }

export {CartContext, CartProvider}
}

Provide context

  • The Providerelement needs to wrap the component tree that will have access to the global data.
  • The value in provider is used when we wrap/provide the provider.
//cart-context.js

import React, { createContext } from 'react'

export const CartContext = createContext('defaultValue') //creating a context

//This component will contain all functionalities that need to be at a global level.
export const CartProvider = ({ children }) => {
const [cartState, setCartState] = useState({})

  const value = {
    cartState,
    setCartState,
  }

//This means all the children component of the CartProvider will have access to vaue prop.
  return <CartContext.Provider value={value}>{children}</CartContext.Provider>

export {CartContext, CartProvider}
}

Wrapping the Components with Provider

//index.js
import React from 'react'

import { CartProvider } from './cart-context'
import { PaymentComponent } from './PaymentComponent'

//wrapping all the components that needs cart data inside the CarProvider 
export const Page = () => {
  return (
    <div>
      <CartProvider>
        <PaymentComponent />
        <App/>
      </CartProvider>
    </div>
  )
}

Consume Context

  • The useContext() hook allows you to access the global data from any child components in the component tree under the Providerwrapper.
  • Destructing of various types are done here so that they can be used
//PaymentComponent.js

import React, { useContext } from 'react'

import { CartContext } from './cart-context'

export const PaymentComponent = () => {
  const { cartState } = useContext(CartContext)
//now the PaymentComponent has access to cartState

  return null
}

When to use useContext?

The main purpose of context is to make data accessible to components without passing it through props. I.e., context prevents prop drilling, where you have to pass down props from parents to children.

Some places where context can be used -

  • Theme data (like dark or light mode)
  • User data (the currently authenticated user)
  • Location-specific data (like user language)

Context works fine for small to medium application. But as the scale increases various problems are present:

  • it is not designed for frequent updates
  • async operations are tricky
  • it has performance limitations
  • does not support selectors
  • you cannot prevent re-renders
  • correctly handling provider-less context is hard