Каждый раз когда мы пишем код:
const [count, setCount] = useState(0)
Под капотом
React запускается целый механизм отслеживания состояния, основанная на структуре Fiber и связанном списке хуков. Эта архитектура позволяет React помнить значения между рендерами и обновлять только нужные части интерфейса.Но для начала давайте посмотрим на основую реализацию хука в файле ReactHooks.js
javascript
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
Это публичное
API хука useState. На входе — начальное значение initialState, которое может быть значением или функцией.Через
resolveDispatcher() получаем текущий диспетчер (ReactCurrentDispatcher.current) — объект, содержащий реализацию хуков для текущей фазы работы React.Диспетчер — объект, который содержит реализацию всех хуков для текущей фазы работы компонента (
mount/update/rerender).React использует разные диспетчеры в зависимости от контекста:- При первом рендере —
mountState- При обновлении —
updateState- При повторном рендере —
rerenderStateПока опустим реализацию каждого, но важно: создаётся новый
hook, который попадает в связанный список хуков, хранящийся в поле memoizedState текущей fiber node.👉 Почему порядок хуков важен?
React полагается на порядок вызова хуков, чтобы правильно связать текущий
hook с соответствующим fiber. Именно поэтому нельзя вызывать хуки внутри условий или циклов.На этапе монтирования
useState создаёт редьюсер basicStateReducer:ReactFiberHooks.js
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
return typeof action === 'function' ? action(state) : action;
}
Базовый редьюсер показывает, как обрабатываются обновления состояния:
- Если мы передаете функцию
setState(prev => prev + 1) она вызывается с предыдущим состоянием- Если вы передаете значение
setState(42) оно становится новым состояниемВводный итог
Итак, мы можем сделать вывод по ключевым особенностям
useState. Каждый, из которых, мы будем изучать подробнее в отдельных постах. 1. Ленивая инициализация — функция инициализации вызывается только один раз, при первом рендере.
2. Пакетная обработка — несколько вызовов
setState могут быть объединены в одно обновление.3. Изолированность — каждый вызов
useState создаёт отдельный hook, независимо от других.4. Стабильная функция обновления —
setState сохраняет идентичность между рендерами.useState — это удобный интерфейс, построенный на связке: Fiber + очередь хуков + диспетчер. В следующих постах мы разберём реализацию setState и напишем простую версию useState для лучшего понимания.---
#React #Hooks #useState #Fiber #Frontend #JavaScript #8bitJS