React Context : The fundamentals you must know

In this post, I am going to help you understand the fundamental concepts of React Context. We will discuss the main components that you need to create and use React Context. We are also going to see the use cases of React Context, compare its advantages with disadvantages, and, finally see when to use React Context and when to avoid it.

Why React Context

Data flow in React applications is unidirectional, which means data passes from parent components to child components. These data pass via props ( Properties ) from the parent component to the child component. 

This parent, child, and prop system works fine with small applications. However, as the application gets larger, it can have nested child components creating a tree of components. Sharing data between top-level parent components to one of the children in the lowest ( deepest ) level of this component tree can be cumbersome. This situation known as “prop drilling”. “Prop drilling” make your code not only verbose code but also can affect the performance of the application. In addition, fixing bugs can be more challenging.

prop drilling: why React Context

What is React context?

React context is a storage to hold data that is common to child components. Imagine, you have a mid to large-size React application with nested child components. With React context, you do not need pass data from a top-level parent component to child component at the deep level of the component tree. Instead of passing data via props, you store the data in React context. Then, the child components can use the data in the Context.

React context

How to make use React context

There are three steps you need to do to utilize React Context in your application.  

components of React Context

1. Create a Context

To create a context in React, you can use the createContext() function provided by React. Here’s how you can create a context:

//Import the necessary dependencies
import React, { createContext } from 'react';

//Create the context using createContext(). defaultValue is optional
const MyContext = createContext(defaultValue);

//Export the context object
export default MyContext;

2. Create a Context provider

A context provider is a component that supplies the context values to its descendant components. It is responsible for defining and sharing the data or state that can be accessed by components that use/consume the context.

context provider is created using the Context.Provider component provided by the context object. The provider component accepts a value prop, which represents the data or state to be shared with the consuming components.

export default function MyContextProvider({ children }) {  
  const contextValue = { message:'Hello from the context!'}; 
  return(
    <MyContext.Provider value={contextValue}>
        {children}   
    </MyContext.Provider>
);
}

Inside the provider component, the contextValue is the data or state that we want to share with the consuming components. In this case, our contextValue is an object with a  message property.

MyContextProvider component expects a children prop. The children prop is then rendered inside the MyContext.Provider component, which makes the context values available to all the descendants of the provider component. value prop represents the context values that you want to provide.

When you want to use the provider, you need to wrap a portion of your component tree with the provider component (<MyContextProvider>), the context values defined in the provider will be accessible to the consuming components within that tree. 

function App() {

 const contextValue = 'Hello from context!'; 
       return ( 
            <MyContext.Provider value={contextValue}> 
                    <Component1 /> 
                    <Component2 />  
             </MyContext.Provider> ); 
}

3. Consume the Context.

There are two ways to use or consume the Context.

1. Using useContext hook

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

export default  function MyComponent() {
  // Consume the context values using the useContext() hook
  const contextValue = useContext(MyContext);
  return (
    <div>
      <p>Context Value: {contextValue}</p>
    </div>
  );
}

The useContext() hook takes the context object ( MyContext ) as an argument and returns the current value of the context. In this case, contextValue will hold the context value provided by the nearest MyContext.Provider ancestor component.

2. Using MyContext.Consumer component

import React from 'react';
import { MyContext } from './MyContextProvider';

export default function MyComponent() {
  return (
    <div>
      <MyContext.Consumer>
        {(contextValue) => (
          <p>Context Value: {contextValue}</p>
        )}
      </MyContext.Consumer>
    </div>
  );
};

The <MyContext.Consumer> component is used to consume the context values within your component. It follows the render prop pattern, which means it expects a function as its child. This function receives the current context value as an argument and returns the JSX that should be rendered.

What are the Use cases of React context

Some of the use cases of React Context are:

  1. Theming: Allowing components to dynamically change their visual styles based on the selected theme.
  2. Localization: Providing translated strings or language settings to components for internationalization purposes.
  3. User Authentication: Sharing user authentication status or user information across multiple components.
  4. State Management: Replacing or supplementing state management libraries like Redux for smaller-scale applications.
  5. Dark Mode: Enabling components to switch between light and dark mode based on user preferences.
  6. Dynamic Configurations: Sharing configuration settings or variables across multiple components.
  7. Component Communication: Facilitating communication between unrelated components without passing props through intermediate components.
  8. App-wide Settings: Sharing app-wide settings or preferences across different parts of the application.
  9. Multi-step Wizards: Managing and sharing state between different steps of a multi-step form or wizard.
  10. Caching and Data Fetching: Caching fetched data and sharing it among components to avoid redundant API requests.

Please note this is not an exclusive list. There can be many other cases you can use React Context.

What are the advantage and disadvantages of using React context

While React Context offers many advantages, it can also introduce some disadvantages too. Some of them are:

Advantages of React ContextPotential Issues (Disadvantages)
Provides a centralized way to share data and state across components.Simplifies app-wide settings or configuration sharing across components.
Helps avoid prop drilling and makes the component tree more readable and maintainable.Performance impact due to unnecessary re-renders caused by context updates.
Reduces the need for passing props through intermediate components.Overuse of global state in context can lead to a global state anti-pattern.
Enables the creation of reusable components that can adapt to different contexts.Context overuse can result in a tightly-coupled and less flexible component tree.
Simplifies app-wide settings or configurations sharing across components.Context dependencies can make reusability and refactoring more challenging.
Facilitates dynamic theming and customization of component styles.Testing components dependent on context may require proper provisioning or mocking.

When to use React Context

  1. You have data or state that needs to be shared across multiple components without passing props through intermediate components.
  2. You have a small to medium-sized application where a centralized state management solution like Redux might be overkill.
  3. You want to avoid prop drilling and make your component tree more maintainable and readable.
  4. You have a few critical pieces of global or app-wide state that need to be accessible by various components.
  5. You want to create reusable components that can adapt to different contexts and environments.

When not to use React Context

  1. You have a large-scale application with complex state management requirements that might be better suited for a dedicated state management library like Redux.
  2. Performance is a critical concern, as frequent context updates and unnecessary re-renders can impact performance.
  3. Overuse of context can lead to a tightly-coupled component tree and make code maintenance and refactoring challenging.
  4. The context value is constantly changing or requires frequent updates, as this can impact performance and complicate the codebase.

Conclusion

In summary, React Context provides a convenient way to share data and states across components in a React application. It offers advantages such as centralized data management, reduced prop drilling, improved code readability, and the ability to create reusable components. However, it’s important to be cautious of potential challenges like increased complexity, performance impacts, overuse of global state, context dependencies, and testing complexities. By carefully considering the specific requirements and trade-offs of your project, you can determine whether React Context is a suitable choice for your application.

Resources

React Context official documentation

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top