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.
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
, andComponentD
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.
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.