oxc-project/oxc · warning · OxcDiagnostic

The Context `value` prop should not be constructed.

Error message

The Context `value` prop should not be constructed.

What it means

Diagnostic from react/jsx-no-constructed-context-values. A React context Provider's value prop was assigned a freshly constructed value (object literal, array literal, new expression, inline call result, etc.). Such a value gets a new identity on every render, so every consumer of the context re-renders each time the provider renders, even when nothing changed. The help suggests useMemo()/useCallback(), a constant value, or hoisting the value out of the render function when it does not depend on props or state.

Source

Thrown at crates/oxc_linter/src/rules/react/jsx_no_constructed_context_values.rs:19

use oxc_ast::{
    AstKind,
    ast::{
        Expression, IdentifierReference, JSXAttributeItem, JSXAttributeName, JSXAttributeValue,
        JSXOpeningElement,
    },
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};

use crate::{
    AstNode,
    context::{ContextHost, LintContext},
    rule::Rule,
};

fn jsx_no_constructed_context_values(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("The Context `value` prop should not be constructed.")
        .with_help("Wrap the `value` prop in useMemo() or useCallback(), or use a constant value to prevent unnecessary re-renders.\nAlternatively, move the value outside the render function if it doesn't depend on props or state.")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct JsxNoConstructedContextValues;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallows JSX context provider values that cause needless re-renders.
    ///
    /// ### Why is this bad?
    ///
    /// 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 render.
    /// This makes the context think it has gotten a new object and can cause needless re-renders

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Wrap the value in useMemo (and callbacks in useCallback): const value = useMemo(() => ({ theme, setTheme }), [theme]);
  2. If the value is constant, define it outside the component or as a module-level constant
  3. If the value depends only on setState-stable setters, memoize with an empty/stable dependency list
  4. For values that genuinely must change every render, reconsider whether context is the right channel, or split the context so consumers subscribe only to changing slices

Example fix

// before
<UserContext.Provider value={{ user, logout }}>
  <App />
</UserContext.Provider>

// after
const value = useMemo(() => ({ user, logout }), [user, logout]);
<UserContext.Provider value={value}>
  <App />
</UserContext.Provider>
Defensive patterns

Strategy: validation

Validate before calling

npx oxlint -D react/jsx-no-constructed-context-values src/

Prevention

When it happens

Trigger: <ThemeContext.Provider value={{ theme, setTheme }}>, value={{ count: 0 }}, value={new Set([a, b])}, value={[state, setState]} or any value={buildValue()} where the expression constructs a new reference inline in the provider element.

Common situations: Auth/user contexts built inline in an App component; theme or feature-flag objects assembled per render; performance regressions discovered after profiling where all context consumers re-render on every parent render.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/4d0fd22540fec068. Report an issue: GitHub.