Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is React Context?

React Context is a powerful feature in React that allows you to share data between components without having to pass it through props. If you are familiar with React, you have probably used props to pass data from parent components to their children. This is a great way to share data between components that are directly related. However, when you have a deep component tree, passing data through props can become tedious and difficult to maintain. This is where React Context comes in handy.

In this blog post, we will dive deep into the world of React Context and learn how to use it effectively in your projects. We will cover the following topics:

  1. Why use React Context?
  2. When should you use React Context?
  3. How to create and use a Context
  4. Context and performance optimizations

Let's get started!

1. Why use React Context?

Imagine you are building a large-scale application with many components that need to share some data. You could pass this data through props from the top-level component down to the components that need it. However, this can quickly become cumbersome and difficult to manage. Additionally, it can lead to unnecessary re-rendering of components that don't care about the data being passed down.

React Context is a feature that allows you to easily share data between components without having to pass it through props. It can greatly simplify your code and make it more maintainable.

Let's take a look at an example. Imagine you have an app with a dark mode and light mode, and you want to store the current theme in a top-level component. You could pass the theme down through props, but that could get annoying if you have many nested components. Instead, you could use React Context to share the theme data with any component that needs it.

2. When should you use React Context?

React Context is a great solution for sharing data between components that are not directly related or when you want to avoid prop drilling (passing data through multiple components just to get it to the components that need it). Some common use cases for React Context include:

  • Theme management (e.g., dark mode and light mode)
  • User authentication and authorization data
  • Localization and internationalization data
  • Global state management (e.g., replacing Redux)

However, you should be cautious when using React Context. Overusing it can lead to unnecessary complexity and cause performance issues. It's essential to strike a balance between using props and context, depending on your specific use case.

3. How to create and use a Context

Now that we understand why and when to use React Context, let's see how we can create and use a Context in our application. We will be building a simple app that allows users to toggle between dark mode and light mode.

Step 1: Create a context

First, we need to create a context using the React.createContext() function. This function returns an object with two components: a Provider and a Consumer. The Provider component is used to set the value of the context, and the Consumer component is used to access the value of the context.

import React from 'react';

const ThemeContext = React.createContext();

Step 2: Provide the context value

Next, we need to use the Provider component to set the value of our context. We will do this in our top-level component (usually App.js). In this example, we will store the current theme ('light' or 'dark') and a function to toggle the theme.

import React, { useState } from 'react';
import ThemeContext from './ThemeContext';

function App() {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {/* Your application components */}
    </ThemeContext.Provider>
  );
}

export default App;

Step 3: Consume the context value

Now that we have our context set up, we can use the Consumer component to access the context value in any of our components. In this example, we will create a ThemeButton component that shows the current theme and toggles the theme when clicked.

import React from 'react';
import ThemeContext from './ThemeContext';

function ThemeButton() {
  return (
    <ThemeContext.Consumer>
      {({ theme, toggleTheme }) => (
        <button onClick={toggleTheme}>
          Current theme: {theme}
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

export default ThemeButton;

Alternatively, you can use the useContext() hook to access the context value in function components:

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

function ThemeButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button onClick={toggleTheme}>
      Current theme: {theme}
    </button>
  );
}

export default ThemeButton;

That's it! Now, any component that needs the theme data can use the Consumer component or the useContext() hook to access it, without having to pass the data through props.

4. Context and performance optimizations

While React Context is great for sharing data between components, it can have performance implications if not used correctly. When a context value changes, all components that consume the context will re-render, even if they don't need the updated value.

To avoid unnecessary re-renders, you can use the React.memo() function to memoize your components. This function will prevent a component from re-rendering if its props have not changed.

import React, { useContext, memo } from 'react';
import ThemeContext from './ThemeContext';

function ThemeButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button onClick={toggleTheme}>
      Current theme: {theme}
    </button>
  );
}

export default memo(ThemeButton);

Another performance optimization technique is to split your context into multiple contexts if different components consume different parts of the context. This way, components will only re-render when the part of the context they need changes.

For example, if you have a context with user data and theme data, you could split it into two separate contexts: UserContext and ThemeContext. This way, components that only need the theme data will not re-render when the user data changes, and vice versa.

In conclusion, React Context is a powerful feature that allows you to share data between components with ease. It can help you avoid prop drilling and simplify your code. However, it's essential to use it wisely and consider performance implications. By understanding when and how to use React Context, you can build more maintainable and efficient applications.

Happy coding!