no-unstable-context-value
Full Name in @eslint-react/eslint-plugin
@eslint-react/no-unstable-context-valueFull Name in eslint-plugin-react-x
react-x/no-unstable-context-valuePresets
strict
strict-typescript
strict-type-checked
Description
Prevents non-stable values (i.e., object literals) from being used as a value for Context.Provider.
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
Failing
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>
);
}Passing
import React, { useMemo } from "react";
const MyContext = React.createContext({});
const value = { foo: "bar" };
function MyComponentProvider() {
return (
<MyContext.Provider value={value}>
<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 gotten a new object and can cause needless re-renders and unintended consequences.
This can be a pretty large performance hit because not only will it cause the context providers and consumers to re-render with all the elements in its subtree, the processing for the tree scan React does to render the provider and find consumers is also wasted.
Implementation
See Also
no-unstable-default-props
Prevents usage of referential-type values as default props in object destructuring.