PassFront
  1. PassFront
  2. База знаний
  3. Хуки

Для чего передавать функцию в 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) — обновление от актуального предыдущего значения (серии обновлений, таймеры/подписки со старыми замыканиями, стабильные колбэки).

Другие вопросы раздела