Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build performant React Native and Expo apps with best practices for lists, animations, and navigation
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/react-state-fallback.md
1---2title: Use fallback state instead of initialState3impact: MEDIUM4impactDescription: reactive fallbacks without syncing5tags: state, hooks, derived-state, props, initialState6---78## Use fallback state instead of initialState910Use `undefined` as initial state and nullish coalescing (`??`) to fall back to11parent or server values. State represents user intent only—`undefined` means12"user hasn't chosen yet." This enables reactive fallbacks that update when the13source changes, not just on initial render.1415**Incorrect (syncs state, loses reactivity):**1617```tsx18type Props = { fallbackEnabled: boolean }1920function Toggle({ fallbackEnabled }: Props) {21const [enabled, setEnabled] = useState(defaultEnabled)22// If fallbackEnabled changes, state is stale23// State mixes user intent with default value2425return <Switch value={enabled} onValueChange={setEnabled} />26}27```2829**Correct (state is user intent, reactive fallback):**3031```tsx32type Props = { fallbackEnabled: boolean }3334function Toggle({ fallbackEnabled }: Props) {35const [_enabled, setEnabled] = useState<boolean | undefined>(undefined)36const enabled = _enabled ?? defaultEnabled37// undefined = user hasn't touched it, falls back to prop38// If defaultEnabled changes, component reflects it39// Once user interacts, their choice persists4041return <Switch value={enabled} onValueChange={setEnabled} />42}43```4445**With server data:**4647```tsx48function ProfileForm({ data }: { data: User }) {49const [_theme, setTheme] = useState<string | undefined>(undefined)50const theme = _theme ?? data.theme51// Shows server value until user overrides52// Server refetch updates the fallback automatically5354return <ThemePicker value={theme} onChange={setTheme} />55}56```57