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-rendersView on GitHub (pinned to e1e7af627c)
Solutions
- Wrap the value in useMemo (and callbacks in useCallback): const value = useMemo(() => ({ theme, setTheme }), [theme]);
- If the value is constant, define it outside the component or as a module-level constant
- If the value depends only on setState-stable setters, memoize with an empty/stable dependency list
- 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
- Default to useMemo for context provider values and useCallback for functions inside them
- Hoist constant context values outside the component
- Split large contexts so only consumers of genuinely changing values re-render
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
- ARIA used where native HTML could suffice.
- Using target=`_blank` without rel=`noreferrer` (which implie
- Using target=`_blank` without rel=`noreferrer` or rel=`noope
- all spread attributes are treated as if they contain an unsa
- React Hook {hook_name:?} cannot be called inside a callback.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/4d0fd22540fec068.
Report an issue: GitHub.