logo by @sawaratsuki1004
React
v19.2
Learn
Reference
Community
Blog

Is this page useful?

On this page

  • Overview
  • Rule Details
  • Common Violations
  • Invalid
  • Valid

    react@19.2

  • Overview
  • Hooks
    • useActionState
    • useCallback
    • useContext
    • useDebugValue
    • useDeferredValue
    • useEffect
    • useEffectEvent
    • useId
    • useImperativeHandle
    • useInsertionEffect
    • useLayoutEffect
    • useMemo
    • useOptimistic
    • useReducer
    • useRef
    • useState
    • useSyncExternalStore
    • useTransition
  • المكونات
    • <Fragment> (<>)
    • <Profiler>
    • <StrictMode>
    • <Suspense>
    • <Activity>
    • <ViewTransition> - This feature is available in the latest Canary version of React
  • APIs
    • act
    • addTransitionType - This feature is available in the latest Canary version of React
    • cache
    • cacheSignal
    • captureOwnerStack
    • createContext
    • lazy
    • memo
    • startTransition
    • use
    • experimental_taintObjectReference - This feature is available in the latest Experimental version of React
    • experimental_taintUniqueValue - This feature is available in the latest Experimental version of React
  • react-dom@19.2

  • Hooks
    • useFormStatus
  • المكونات
    • Common (e.g. <div>)
    • <form>
    • <input>
    • <option>
    • <progress>
    • <select>
    • <textarea>
    • <link>
    • <meta>
    • <script>
    • <style>
    • <title>
  • APIs
    • createPortal
    • flushSync
    • preconnect
    • prefetchDNS
    • preinit
    • preinitModule
    • preload
    • preloadModule
  • Client APIs
    • createRoot
    • hydrateRoot
  • Server APIs
    • renderToPipeableStream
    • renderToReadableStream
    • renderToStaticMarkup
    • renderToString
    • resume
    • resumeToPipeableStream
  • Static APIs
    • prerender
    • prerenderToNodeStream
    • resumeAndPrerender
    • resumeAndPrerenderToNodeStream
  • React Compiler

  • Configuration
    • compilationMode
    • gating
    • logger
    • panicThreshold
    • target
  • Directives
    • "use memo"
    • "use no memo"
  • Compiling Libraries
  • React DevTools

  • React Performance tracks
  • eslint-plugin-react-hooks

  • Lints
    • exhaustive-deps
    • rules-of-hooks
    • component-hook-factories
    • config
    • error-boundaries
    • gating
    • globals
    • immutability
    • incompatible-library
    • preserve-manual-memoization
    • purity
    • refs
    • set-state-in-effect
    • set-state-in-render
    • static-components
    • unsupported-syntax
    • use-memo
  • Rules of React

  • Overview
    • Components and Hooks must be pure
    • React calls Components and Hooks
    • Rules of Hooks
  • React Server Components

  • Server Components
  • Server Functions
  • Directives
    • 'use client'
    • 'use server'
  • Legacy APIs

  • Legacy React APIs
    • Children
    • cloneElement
    • Component
    • createElement
    • createRef
    • forwardRef
    • isValidElement
    • PureComponent
API Reference
Lints

set-state-in-effect

Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance.

Rule Details

Setting state immediately inside an effect forces React to restart the entire render cycle. When you update state in an effect, React must re-render your component, apply changes to the DOM, and then run effects again. This creates an extra render pass that could have been avoided by transforming data directly during render or deriving state from props. Transform data at the top level of your component instead. This code will naturally re-run when props or state change without triggering additional render cycles.

Synchronous setState calls in effects trigger immediate re-renders before the browser can paint, causing performance issues and visual jank. React has to render twice: once to apply the state update, then again after effects run. This double rendering is wasteful when the same result could be achieved with a single render.

In many cases, you may also not need an effect at all. Please see You Might Not Need an Effect for more information.

Common Violations

This rule catches several patterns where synchronous setState is used unnecessarily:

  • Setting loading state synchronously
  • Deriving state from props in effects
  • Transforming data in effects instead of render

Invalid

Examples of incorrect code for this rule:

// ❌ Synchronous setState in effect function Component({data}) { const [items, setItems] = useState([]); useEffect(() => { setItems(data); // Extra render, use initial state instead }, [data]); } // ❌ Setting loading state synchronously function Component() { const [loading, setLoading] = useState(false); useEffect(() => { setLoading(true); // Synchronous, causes extra render fetchData().then(() => setLoading(false)); }, []); } // ❌ Transforming data in effect function Component({rawData}) { const [processed, setProcessed] = useState([]); useEffect(() => { setProcessed(rawData.map(transform)); // Should derive in render }, [rawData]); } // ❌ Deriving state from props function Component({selectedId, items}) { const [selected, setSelected] = useState(null); useEffect(() => { setSelected(items.find(i => i.id === selectedId)); }, [selectedId, items]); }

Valid

Examples of correct code for this rule:

// ✅ setState in an effect is fine if the value comes from a ref function Tooltip() { const ref = useRef(null); const [tooltipHeight, setTooltipHeight] = useState(0); useLayoutEffect(() => { const { height } = ref.current.getBoundingClientRect(); setTooltipHeight(height); }, []); } // ✅ Calculate during render function Component({selectedId, items}) { const selected = items.find(i => i.id === selectedId); return <div>{selected?.name}</div>; }

When something can be calculated from the existing props or state, don’t put it in state. Instead, calculate it during rendering. This makes your code faster, simpler, and less error-prone. Learn more in You Might Not Need an Effect.

Previousrefs
Nextset-state-in-render

Copyright © Meta Platforms, Inc
no uwu plz
uwu?
Logo by@sawaratsuki1004
Learn React
Quick Start
Installation
Describing the UI
Adding Interactivity
Managing State
Escape Hatches
API Reference
React APIs
React DOM APIs
Community
Code of Conduct
Meet the Team
Docs Contributors
Acknowledgements
More
Blog
React Native
Privacy
Terms
// ❌ Synchronous setState in effect
function Component({data}) {
const [items, setItems] = useState([]);

useEffect(() => {
setItems(data); // Extra render, use initial state instead
}, [data]);
}

// ❌ Setting loading state synchronously
function Component() {
const [loading, setLoading] = useState(false);

useEffect(() => {
setLoading(true); // Synchronous, causes extra render
fetchData().then(() => setLoading(false));
}, []);
}

// ❌ Transforming data in effect
function Component({rawData}) {
const [processed, setProcessed] = useState([]);

useEffect(() => {
setProcessed(rawData.map(transform)); // Should derive in render
}, [rawData]);
}

// ❌ Deriving state from props
function Component({selectedId, items}) {
const [selected, setSelected] = useState(null);

useEffect(() => {
setSelected(items.find(i => i.id === selectedId));
}, [selectedId, items]);
}
// ✅ setState in an effect is fine if the value comes from a ref
function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);

useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
}, []);
}

// ✅ Calculate during render
function Component({selectedId, items}) {
const selected = items.find(i => i.id === selectedId);
return <div>{selected?.name}</div>;
}