Codiga has joined Datadog!

Read the Blog·

Interested in our Static Analysis?

Sign up
← All posts
Daniel Strong Saturday, January 14, 2023

Improve React Context performance

Share

AUTHOR

Daniel Strong, Frontend Engineer

Daniel is a Frontend Engineer at Codiga.

He is a passionate frontend engineer, teacher, and learner. He has worked on or led several creative projects where he's grown his leadership, management, design, and programming skills.

See all articles

What is React Context?

React context allows components to share data without having to pass props down through every level of the component tree. React context is primarily used to avoid prop drilling.

In the example below, we see how prop-drilling (or prop-tunneling) is used to pass data from a parent component (ComponentA) through children components (ComponentB and ComponentC) until it gets where it needs to (ComponentD).

// Component A
function ComponentA(props) {
  return <ComponentB data={props.data} />;
}

// Component B
function ComponentB(props) {
  return <ComponentC data={props.data} />;
}

// Component C
function ComponentC(props) {
  return <ComponentD data={props.data} />;
}

// Component D
function ComponentD(props) {
  return <div>{props.data}</div>;
}

As your application grows, this can lead to a lot of unnecessary code and make it hard to understand how data is flowing through your application. Redux, MobX, and other state management libraries recognized this issue and made it easier to manage and share data throughout your application.

However, these solutions were often overkill for most applications and this is where React Context comes in handy. With React context, you can avoid prop-drilling by providing the data at a higher level in the component tree and then consuming it at a lower level, so our example above can be rewritten with React context like so.

// Create the context object
const MyContext = React.createContext();

// Provide the context data
function App() {
  return (
    <MyContext.Provider value="Hello World">
      <ComponentA />
    </MyContext.Provider>
  );
}

// Consume the context data
function ComponentD() {
  const contextValue = React.useContext(MyContext);
  return (
    <MyContext.Consumer>
      <div>{contextValue}</div>
    </MyContext.Consumer>
  );
}

What causes React context performance issues?

Several factors can cause performance issues with React context, but we'll list the most important two:

  • Deep component nesting: The more nested a component is, the more context providers it has to go through. This can lead to unnecessary re-renders, as the component may not need to receive the context value from all of the providers.

  • Unnecessary re-renders: When the context value changes, all components within that context will re-render. In our example above this means that ComponentA, ComponentB, ComponentC, and ComponentD will all re-render if the value changes. This can cause unnecessary re-renders if the context value is not used in a particular component or if the value is not used in a way that affects the component's behavior.

It's important to note that these factors may not be significant in small-scale projects, but they can become problematic in larger, more complex applications.

How to improve React context performance

Avoid deep component nesting: The more nested a component is, the more context providers it has to go through, which can lead to unnecessary re-renders. Don't put all your React context providers at the top level of your app. Try to keep your context component tree as shallow as possible, by wrapping the providers around only the components that need them.

Don't set your React context provider value as non-stable value (i.e. object identities). The examples below can cause unintended re-renders which will hurt performance.

// object
<MyContext.Provider value={{ foo: 'bar' }}>
  <ComponentA />
</MyContext.Provider>

// array
<MyContext.Provider value={[ ...foo, ...bar ]}>
  <ComponentA />
</MyContext.Provider>

// function
<MyContext.Provider value={() => toggle()}>
  <ComponentA />
</MyContext.Provider>

Automatically check for non-stable values

Codiga provides IDE plugins and integrations with GitHub, GitLab, or Bitbucket to detect non-stable values in React context providers. The Codiga static code analysis detects this issue directly in your IDE or code reviews.

This rule generates a warning when the value of a React context provider is not set to a stable value.

No constructed context values rule

To use this rule consistently, along with many other React best practices, all you need to do is to install the integration in your IDE (for VS Code or JetBrains) or code management system and add a codiga.yml file at the root of your project with the following content:

rulesets:
  - react-best-practices

You can also navigate to your project directory in your terminal and run the following command to get started.

npx @codiga/cli ruleset-add react-best-practices

It will then check all your Javascript and Typescript code against 15+ React best practice rules.

More Resources

Are you interested in Datadog Static Analysis?

Sign up