no-unstable-context-value
Prevents non-stable values (i.e., object literals) from being used as a value for 'Context.Provider'.
Full Name in eslint-plugin-react-x
react-x/no-unstable-context-valueFull Name in @eslint-react/eslint-plugin
@eslint-react/no-unstable-context-valuePresets
strict
strict-typescript
strict-type-checked
Rule Details
React will re-render all consumers of a context whenever the context value changes, and if the value is not stable this can lead to unnecessary re-renders.
Examples
Creating a new object as the Context value on every render
JavaScript objects and functions get a new reference every time they are recreated. If you pass an object literal directly in JSX, the Provider will think the value has changed on every render, causing all consumers to re-render unnecessarily.
// Problem: Object literals create a new reference on every render
import React from "react";
const MyContext = React.createContext({});
function MyComponentProvider() {
return (
<MyContext.Provider value={{ foo: "bar" }}>
{/* ^^^^^^^^^^^^^^ */}
{/* - An 'Object literal' passed as the value prop to the context provider should not be constructed. It will change on every render. Consider wrapping it in a useMemo hook. */}
<ExampleConsumer />
</MyContext.Provider>
);
}// Recommended: Lift the value to module scope or use useMemo to keep the reference stable
import React, { useMemo } from "react";
const MyContext = React.createContext({});
const value = { foo: "bar" };
function MyComponentProvider() {
return (
<MyContext.Provider value={value}>
<ExampleConsumer />
</MyContext.Provider>
);
}Using the React 19 use memo directive
In React 19, if a component uses the "use memo" directive, the compiler automatically keeps object references stable, so passing object literals directly is acceptable.
// OK: With the use memo directive, the compiler automatically optimizes references
import React from "react";
const MyContext = React.createContext({});
function MyComponentProvider() {
"use memo";
return (
<MyContext.Provider value={{ foo: "bar" }}>
<ExampleConsumer />
</MyContext.Provider>
);
}Legitimate Uses
React Context and all its child nodes and consumers are re-rendered whenever the value prop changes. Because each JavaScript object carries its own identity, things like object expressions ({foo: 'bar'}) or function expressions get a new identity on every run through the component. This makes the context think it has received a new object and can cause needless re-renders and unintended consequences.
This can be a large performance hit because not only will it cause the context providers and consumers to re-render with all the elements in their subtree, the processing for the tree scan React does to render the provider and find consumers is also wasted.
Versions
Resources
Further Reading
See Also
react-x/no-unstable-default-props
Prevents using referential-type values as default props in object destructuring.