Try @eslint-react/kit@beta
logoESLint React

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-value

Full Name in @eslint-react/eslint-plugin

@eslint-react/no-unstable-context-value

Presets

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

On this page