fork API

fork API

import { fork, type Scope } from "effector";

Метод fork создает изолированный скоуп приложения. Он нужен для SSR, тестирования и локальной изоляции состояния — вы запускаете вычисления в копии без влияния на глобальные юниты.

Алгоритм работы

  1. Вы вызываете fork, получая новый скоуп.
  2. Если переданы values или handlers, они применяются при создании этого скоупа.
  3. Юниты, вызванные с этим скоупом, работают с изолированными значениями и обработчиками.
  4. Состояние читается через scope.getState(store) или сериализуется через serialize.

Виды конфигураций fork

Форма
Описание
fork()Создает новый чистый скоуп без предзаполненных данных и переопределений обработчиков.
fork({ values?, handlers? })Создает скоуп с начальными значениями сторов и пользовательскими обработчиками эффектов.
fork(domain, options?)Устаревшая форма, требующая domain. Используйте fork({ values?, handlers? }), если нет зависимости от старой сигнатуры.

Конфигурации

fork()

Создает новый прикладной скоуп без дополнительных настроек.

  • Формула
fork(): Scope
  • Тип
type SerializedState = Record<string, unknown>;
type StorePair<T = unknown> = [StoreWritable<T>, T];
export function fork(config?: {
values?: StorePair<any>[] | SerializedState;
handlers?: Array<[Effect<any, any, any>, Function]>;
}): Scope;
  • Особенности

    • Возвращает новый скоуп без предзаполненных сторов и без замены обработчиков.
    • Подходит, когда данные и побочные эффекты должны остаться неизменными (например, первый рендер на сервере).
  • Примеры

import { createStore, createEvent, fork, allSettled } from "effector";
const inc = createEvent();
const dec = createEvent();
const $counter = createStore(0);
$counter.on(inc, (value) => value + 1);
$counter.on(dec, (value) => value - 1);
const scopeA = fork();
const scopeB = fork();
await allSettled(inc, { scope: scopeA });
await allSettled(dec, { scope: scopeB });
console.log($counter.getState()); // => 0
console.log(scopeA.getState($counter)); // => 1
console.log(scopeB.getState($counter)); // => -1
  • Возвращаемое значение

Новый скоуп.

fork({ values?, handlers? })

Позволяет задать начальные значения для сторов и переопределить обработчики эффектов внутри скоупа.

  • Формула
fork({
values?, // например [[$store, value], ...] или сериализованный объект
handlers?, // например [[effect, handler], ...]
}): Scope
  • Тип
type SerializedState = Record<string, unknown>;
type StorePair<T = unknown> = [StoreWritable<T>, T];
export function fork(config?: {
values?: StorePair<any>[] | SerializedState;
handlers?: Array<[Effect<any, any, any>, Function]>;
}): Scope;
  • Особенности

    • values может быть массивом кортежей [$store, value] или объектом сериализованного состояния (обычно результат serialize); предпочтителен массив кортежей.
    • handlers принимает только массив кортежей, замены работают только в пределах созданного скоупа.
    • Значения и обработчики применяются один раз при создании скоупа и не обновляются автоматически.
  • Примеры

Задание начального состояния и подмена обработчика в тесте:

import { createEffect, createStore, fork, allSettled } from "effector";
const fetchFriendsFx = createEffect<{ limit: number }, string[]>(async ({ limit }) => {
return [];
});
const $user = createStore("guest");
const $friends = createStore<string[]>([]);
$friends.on(fetchFriendsFx.doneData, (_, result) => result);
const testScope = fork({
values: [[$user, "alice"]],
handlers: [[fetchFriendsFx, () => ["bob", "carol"]]],
});
await allSettled(fetchFriendsFx, {
scope: testScope,
params: { limit: 10 },
});
console.log(testScope.getState($friends));
// => ['bob', 'carol']

Создание скоупа с сериализованным состоянием:

import { fork } from "effector";
const serialized = {
userSid: "alice",
ageSid: 21,
};
const scope = fork({ values: serialized });
  • Возвращаемое значение

Новый скоуп с примененными values и handlers.

fork(domain, options?)

Устаревшая форма, требующая domain; актуальна только для совместимости со старым кодом.

Устарело

Используйте fork({ values?, handlers? }), так как fork отслеживает юниты автоматически без передачи domain.

  • Формула
fork(domain, {
values?, // например [[$store, value], ...] или сериализованный объект
handlers?, // например [[effect, handler], ...]
}): Scope
  • Тип
type SerializedState = Record<string, unknown>;
export function fork(
domain: Domain,
config?: {
values?: SerializedState | Array<[StoreWritable<any>, any]>;
handlers?: Array<[Effect<any, any, any>, Function]>;
},
): Scope;
  • Особенности

    • Передача domain нужна только в проектах, где код еще зависит от старой сигнатуры.
    • Допустимые форматы values и handlers совпадают с конфигурацией без domain.
  • Пример

import { createDomain, createStore, fork } from "effector";
const app = createDomain();
const $flag = app.createStore(false);
const scope = fork(app, {
values: [[$flag, true]],
});
console.log(scope.getState($flag)); // => true
  • Возвращаемое значение

Новый скоуп, привязанный к указанному domain.

Перевод поддерживается сообществом

Документация на английском языке - самая актуальная, поскольку её пишет и обновляет команда effector. Перевод документации на другие языки осуществляется сообществом по мере наличия сил и желания.

Помните, что переведенные статьи могут быть неактуальными, поэтому для получения наиболее точной и актуальной информации рекомендуем использовать оригинальную англоязычную версию документации.

Соавторы