avoidAdjustingStateWhenAPropChangesAvoid adjusting state when a prop changes. Instead, adjust "{{state}}" directly during render when {{props}} changes, or refactor your state to avoid this need entirely.small-rules/no-adjust-state-on-prop-changeDisallow adjusting state in an effect when a prop changes.
Ported from
eslint-plugin-react-you-might-not-need-an-effect/no-adjust-state-on-prop-change.
The upstream rule points at the “Adjusting some state when a prop
changes”
section of the React docs, so that’s where the intent comes from.
The shape this flags is an effect whose dependencies include a prop, and whose body synchronously writes state. What you’ve built is a prop-to-state sync, and it costs you two renders: the prop arrives, you render with the old state, then the effect fires and you render again with the corrected one. In between, the UI shows state that’s already wrong. On Roblox that usually shows up as a textlabel or a frame popping in a frame late.
The fix is usually to not copy the prop into state at all. Compute what you need during render and let the prop stay the source of truth. If the state genuinely has its own lifecycle, there are better tools than an effect for resetting it, but more often than not the honest answer is that the state shouldn’t exist.
avoidAdjustingStateWhenAPropChangesAvoid adjusting state when a prop changes. Instead, adjust "{{state}}" directly during render when {{props}} changes, or refactor your state to avoid this need entirely.This rule accepts one options object after the severity.
import React, { useEffect, useState } from "@rbxts/react";
export function List({ items }: { items: ReadonlyArray<string> }): React.Element { const [selection, setSelection] = useState<string | undefined>();
useEffect(() => { setSelection(undefined); }, [items]);
return <textlabel Text={selection} />;}import React, { useState } from "@rbxts/react";
export function List({ items }: { items: ReadonlyArray<string> }): React.Element { const [selection, setSelection] = useState<string | undefined>(undefined); const [previousItems, setPreviousItems] = useState(items);
if (items !== previousItems) { setPreviousItems(items); setSelection(undefined); }
return <textlabel Text={selection} />;}