Rules
no-unstable-context-value

no-unstable-context-value

Rule category

Perf.

What it does

Prevents non-stable values (i.e. object literals) from being used as a value for Context.Provider.

Why is this bad?

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 const ExampleContext: React.Context<{}>ExampleContext = React.function React.createContext<{}>(defaultValue: {}): React.Context<{}>
Lets you create a {@link Context } that components can provide or read.
@paramdefaultValue The value you want the context to have when there is no matching {@link Provider} in the tree above the component reading the context. This is meant as a "last resort" fallback.@see{@link https://react.dev/reference/react/createContext#reference React Docs}@see{@link https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context/ React TypeScript Cheatsheet}@example```tsx import { createContext } from 'react'; const ThemeContext = createContext('light'); ```
createContext
({});
function function ExampleProvider(): React.JSX.ElementExampleProvider() { return ( <const ExampleContext: React.Context<{}>ExampleContext.React.Context<{}>.Provider: React.Provider<{}>Provider React.ProviderProps<{}>.value: {}value={{ foo: stringfoo: "bar" }}> <const ExampleConsumer: React.ComponentType<{}>ExampleConsumer /> </const ExampleContext: React.Context<{}>ExampleContext.React.Context<{}>.Provider: React.Provider<{}>Provider> ); } declare const const ExampleConsumer: React.ComponentType<{}>ExampleConsumer: React.type React.ComponentType<P = {}> = React.ComponentClass<P, any> | React.FunctionComponent<P>
Represents any user-defined component, either as a function or a class. Similar to {@link JSXElementConstructor } , but with extra properties like {@link FunctionComponent.defaultProps defaultProps } and {@link ComponentClass.contextTypes contextTypes } .
@templateP The props the component accepts.@see{@link ComponentClass}@see{@link FunctionComponent}
ComponentType
;

Passing

import React, { function useMemo<T>(factory: () => T, deps: DependencyList): T
`useMemo` will only recompute the memoized value when one of the `deps` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useMemo}
useMemo
} from "react";
const const ExampleContext: React.Context<{}>ExampleContext = React.function React.createContext<{}>(defaultValue: {}): React.Context<{}>
Lets you create a {@link Context } that components can provide or read.
@paramdefaultValue The value you want the context to have when there is no matching {@link Provider} in the tree above the component reading the context. This is meant as a "last resort" fallback.@see{@link https://react.dev/reference/react/createContext#reference React Docs}@see{@link https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context/ React TypeScript Cheatsheet}@example```tsx import { createContext } from 'react'; const ThemeContext = createContext('light'); ```
createContext
({});
const const value: {
foo: string;
}
value
= { foo: stringfoo: "bar" };
function function ExampleProvider(): React.JSX.ElementExampleProvider() { return ( <const ExampleContext: React.Context<{}>ExampleContext.React.Context<{}>.Provider: React.Provider<{}>Provider React.ProviderProps<{}>.value: {}value={const value: {
foo: string;
}
value
}>
<const ExampleConsumer: React.ComponentType<{}>ExampleConsumer /> </const ExampleContext: React.Context<{}>ExampleContext.React.Context<{}>.Provider: React.Provider<{}>Provider> ); } declare const const ExampleConsumer: React.ComponentType<{}>ExampleConsumer: React.type React.ComponentType<P = {}> = React.ComponentClass<P, any> | React.FunctionComponent<P>
Represents any user-defined component, either as a function or a class. Similar to {@link JSXElementConstructor } , but with extra properties like {@link FunctionComponent.defaultProps defaultProps } and {@link ComponentClass.contextTypes contextTypes } .
@templateP The props the component accepts.@see{@link ComponentClass}@see{@link FunctionComponent}
ComponentType
;

Legitimate Uses

React Context, and all its child nodes and Consumers are rerendered 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 rerenders and unintended consequences.

This can be a pretty large performance hit because not only will it cause the context providers and consumers to rerender 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.