TGViewer
8BitJS 8BitJS @eightbitjs · 162 subscribers
Post #12 427
​​Разбор mountState как точки входа в работу useState

Начнем с разбора “точки входа” в архитектуры Fiber и механики работы хуков.

Что делает mountState

При первом рендере компонента React вызывает mountState для инициализации хука. Немного упростим и уберем типизацию внутри исходной функции:

 js
function mountState(
initialState
) {
const hook = mountStateImpl(initialState);
const queue = hook.queue;
const dispatch = dispatchSetState.bind(
null,
currentlyRenderingFiber,
queue,
);
queue.dispatch = dispatch;
return [hook.memoizedState, dispatch];
}


Итак, функция mountState принимает исходное значение и возвращает массив из текущего состояния memoizedState (обратим внимание, что это просто название переменной, а не ее мемоизация в привычном понимании) и функции dispatch для его обновления.

Как создается хук

На первом шаге вызывается mountStateImpl, которая возвращает новый объект хука:

function mountStateImpl(initialState) {
const hook = mountWorkInProgressHook();

if (typeof initialState === 'function') {
const initialStateInitializer = initialState;
initialState = initialStateInitializer();
}

hook.memoizedState = initialState
hook.baseState = initialState;

const queue: UpdateQueue = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState,
};

hook.queue = queue;

return hook;
}


Связанный список хуков

Хук создается в функции mountWorkInProgressHook:

function mountWorkInProgressHook() {
const hook: Hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null,
};

if (workInProgressHook === null) {
currentlyRenderingFiber
.memoizedState = hook
workInProgressHook = hook;
} else {
workInProgressHook = hook
workInProgressHook.next = hook;
}
return workInProgressHook;
}


Все хуки в компоненте организованы в связанный список.
Первый хук хранится в currentlyRenderingFiber.memoizedState, а каждый последующий хук доступен через свойство next предыдущего хука.

Хук хранит два значения: текущего сохраненного значения memoizedState и базового, из промежуточных вычислений, значения baseState.

Аналогично в хуке сохраняются две очереди. Основная очередь обновлений queue, которая содержит все новые обновления, добавленные с момента последнего рендера. Когда вы вызываете функцию-сеттер (например, setState), новое обновление добавляется в эту очередь. baseQueue - это очередь обновлений, которые были пропущены в предыдущем рендере из-за низкого приоритета. Эта очередь используется как отправная точка для следующего рендера.

Также объект хранит ссылку в next на следующий хук.

Вернемся к функции mountStateImpl, далее происходит проверка, является ли начальное значение функцией. Это и есть так называемая lazy initialization:

if (typeof initialState === 'function') {
const initialStateInitializer = initialState;
initialState = initialStateInitializer();
}


React сохраняет функцию в переменной initialStateInitializer, а затем вызывает её и присваивает результат переменной initialState. Таким образом, вместо самой функции в качестве начального состояния используется результат её выполнения.

После этого сохраняем исходное значение в memoizedState и baseState. Создаем новую запись в основной очереди и возвращаем hook. Обратим внимание, что React использует циклическую связанную очередь, но об этом в следующий раз.

Финальный шаг: создаем dispatch

В завершение работы mountState создается функция сеттер на основе функции dispatchSetState с использованием bind для привязки контекста из текущего узла fiber и очереди обновлений для этого узла.

const dispatch = dispatchSetState.bind(
null,
currentlyRenderingFiber,
queue,
);


---

#React #Fiber #useState #mountState #Hooks #LazyInitialization #JavaScript #8bitJS
  • ❤‍🔥 3
  • 🔥 2
More from @eightbitjs
  1. Jul 21, 2026​​Ускоряем O(N + T), не меняя Big O. Часть 5. Зачем здесь WebAssembly После реализации бак…
  2. Jul 18, 2026​​Итоги CodeRun Summer: 15 задач и 636 попыток решения Финал CodeRun Summer Challenge выгл…
  3. Jul 17, 2026​​Ускоряем O(N + T), не меняя Big O. Часть 4. Кэш, бакеты и упаковка событий В предыдущей…
  4. Jul 16, 2026​​Ускоряем O(N + T), не меняя Big O. Часть 3. Как оставить четыре байта и не сломать ответ…
  5. Jul 15, 2026​​Ускоряем O(N + T), не меняя Big O. Часть 2. Четыре байта, которые могут изменить результ…
  6. Jul 14, 2026​​Ускоряем O(N + T), не меняя Big O. Часть 1. Разностный массив — это только начало На про…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →