In a React Native onboarding form, why does typed input survive some Fast Refresh edits but reset on others?
answer
- function components and Hooks only
- extra non-component export resets
- Hook arguments or order changed
- render error: React remounts
- // @refresh reset forces a remount
basics
~20 sFast Refresh keeps state only for function components and Hooks it can match to the previous version. Class components, files with extra non-component exports, changed Hook arguments or order, a render error and // @refresh reset all cause a remount, which resets the typed input.
solid answer
~40 sFast Refresh preserves local state only when it is safe. It keeps state for function components and Hooks, and `useState` and `useRef` keep their values as long as their arguments and the order of Hook calls do not change. State resets when the component is a class (or a higher-order component returns a class), when the edited file exports something besides components, when you add, remove or reorder Hooks or change a Hook's argument, and when a render error made React remount the app. `// @refresh reset` in a file forces its components to remount on every edit. So in an onboarding form, tweaking a label keeps the typed email, while adding a `useState` or exporting a `STEP_TITLES` constant from the same file wipes it.
code
tsx · 16 lines// OnboardingForm.tsx: the extra export below makes every edit reset state
import { useState } from 'react';
import { Text, TextInput, View } from 'react-native';
export const STEP_TITLES = ['Name', 'Email', 'Done'];
export default function OnboardingForm() {
const [step, setStep] = useState(0);
const [name, setName] = useState('');
return (
<View>
<Text>{STEP_TITLES[step]}</Text>
<TextInput value={name} onChangeText={setName} />
</View>
);
}go deeper
Recall that function components and Hooks keep state across edits, while class components do not.
Explain each reset trigger: extra exports, changed Hook arguments or order, a render error, and the @refresh reset directive.
Show you can keep a team's dev loop fast by structuring files so state-heavy screens like multi-step forms rarely lose their input.
Weigh file-structure conventions that favour Fast Refresh against other module-organisation goals, and codify the ones worth enforcing.
## Keeping state is conditional Fast Refresh **tries** to keep local React state in the component you edit, but only when it can tell the component is still "the same component". When it cannot, it **remounts** the component: React throws away the old instance and mounts the new code with fresh state. Fast Refresh keeps state for **function components and Hooks**; everything else is a reason to remount. For a multi-step onboarding form this is the difference between tweaking a label while the user's typed name and email stay put, and being dumped back on an empty step 1 after every save. ## The reasons state resets The React Native docs list these, and each has a concrete cause: | Cause | Why Fast Refresh remounts | What to do | |---|---|---| | **Class component** | only function components and Hooks preserve state | convert to a function component | | **Other exports in the module** | a file exporting a component plus a constant, helper or config is not a pure component module | move the non-component export into its own file | | **A higher-order component that returns a class** | the wrapped result is a class, so the class rule applies | prefer a wrapper that returns a function component | | **Changed Hook arguments or Hook order** | `useState` and `useRef` keep their values only while their arguments and the order of Hook calls stay the same | expect a reset when you add, remove or reorder Hooks | | **A render error** | after a runtime error inside a component, React remounts the app with the fixed code | wrap risky subtrees in an error boundary so it retries there instead | | **`// @refresh reset` in the file** | an explicit request to remount on every edit | remove it once you are done | ## The onboarding form, edit by edit Suppose `OnboardingForm.tsx` holds `const [step, setStep] = useState(0)` and `const [values, setValues] = useState({ name: '', email: '' })`: 1. You change a button label. Same Hooks, same arguments, a function component in a component-only file: the step and the typed values survive. 2. You add `export const STEP_TITLES = [...]` to the same file. The module now has a non-component export, so edits to it reset the form. 3. You add a third `useState` for a checkbox. The Hook list changed, so this edit remounts the component and the form resets once. 4. You change `useState(0)` to `useState(1)` to start on step 2. The Hook's argument changed, so the component remounts and state resets. 5. A typo throws during render. After you fix it, React remounts, and the typed input is gone unless an error boundary around the step caught the error. ## Forcing a reset on purpose Sometimes you **want** a fresh mount — tuning an animation that runs only on mount, or re-checking what the first step looks like. Add the directive anywhere in the file: ```tsx // @refresh reset ``` It is local to that file: components defined there remount on every edit, while the rest of the app keeps its state. ## What does not reset state - Editing styles, JSX, event handlers or effect bodies inside a function component. - Editing a module that only component files import, such as a theme file. - Editing a child component in another file: the parent's state is untouched. ## How to keep the form alive while you work - Keep one component per file and nothing else exported from it. - Put step titles, validation rules and field configs in their own modules. - Add Hooks in one edit and tune them in the next, so only the first edit resets. - Use error boundaries around steps you are actively breaking and fixing.
- What is // @refresh reset for, and how far does it reach?It forces Fast Refresh to remount the components defined in that file on every edit, which is useful when tuning something that runs only on mount, such as an entry animation. It is local to the file: the rest of the app keeps its state.
- How does an error boundary change what happens after a render error during Fast Refresh?Without one, React remounts the app with the fixed code, so you land back at the root screen with fresh state. With an error boundary around the failing subtree, the boundary retries rendering on the next edit, so only that subtree is affected.
saying these in an interview costs you the question
- Fast Refresh preserves state for class components too
- Any edit to a Hook's arguments keeps the old state
- Exporting a constant next to a component has no effect on Fast Refresh
- // @refresh reset remounts the whole app on every edit
- After a render error you must always reload the app manually