Для чего передавать функцию в UseState?
Хуки
Функцию в useState передают в двух местах и с разными целями: как инициализатор (ленивое начальное значение) и как аргумент сеттера (обновление от предыдущего значения).
1. Ленивая инициализация: useState(() => ...)
const [draft, setDraft] = useState(() => {
const saved = localStorage.getItem('draft'); // дорогая операция
return saved ? JSON.parse(saved) : emptyDraft;
});Зачем: выражение-аргумент вычисляется при каждом рендере (даже если результат нужен только первый раз). Функция-инициализатор вызывается один раз при монтировании:
useState(expensiveParse(raw)); // parse на каждый рендер — впустую
useState(() => expensiveParse(raw)); // parse один разИспользовать для: чтения localStorage, парсинга, построения больших структур, генерации id.
2. Функциональное обновление: setState((prev) => ...)
setCount((prev) => prev + 1);Зачем: сеттер с функцией получает актуальное предыдущее значение из очереди обновлений, а не значение из замыкания текущего рендера. Критично когда:
- несколько обновлений подряд:
setCount((c) => c + 1)дважды даст +2;setCount(count + 1)дважды — только +1; - обновление из «старых» замыканий — таймеры, подписки, эффекты с
[]:
useEffect(() => {
const id = setInterval(() => setCount((c) => c + 1), 1000); // всегда актуально
return () => clearInterval(id);
}, []);- бонус: колбэк с функциональным сеттером не зависит от state → useCallback с пустыми deps.
Коротко для собеседования
Две цели: useState(() => init) — ленивый инициализатор, выполняется один раз (экономия на дорогой инициализации); setX((prev) => next) — обновление от актуального предыдущего значения (серии обновлений, таймеры/подписки со старыми замыканиями, стабильные колбэки).