fork

since

Creates an isolated instance of application. Primary purposes of this method are SSR and testing.

Formulae

fork(): Scope
fork(options: { values?, handlers? }): Scope
fork(domain: Domain, options?: { values?, handlers? }): Scope

Arguments

  1. domain (Domain): Optional domain to fork

  2. values: Option to provide initial states for stores

    Can be used in three ways:

    1. Array of tuples with stores and values:

      fork({
        values: [
          [$user, "alice"],
          [$age, 21],
        ],
      });
    2. Map with stores and values:

      fork({
        values: new Map().set($user, "alice").set($age, 21),
      });
    3. Plain object: {[sid: string]: value}

      fork({
        values: {
          [$user.sid]: "alice",
          [$age.sid]: 21,
        },
      });
      Explanation

      Such objects are created by serialize, in application code array of tuples is preferred

  3. handlers: Option to provide handlers for effects

    Can be used in different ways:

    1. Array of tuples with effects and handlers:

      fork({
        handlers: [
          [getMessageFx, (params) => ({ id: 0, text: "message" })],
          [getUserFx, async (params) => ({ name: "alice", age: 21 })],
        ],
      });
    2. Map with effects and handlers:

      fork({
        handlers: new Map()
          .set(getMessageFx, (params) => ({ id: 0, text: "message" }))
          .set(getUserFx, async (params) => ({ name: "alice", age: 21 })),
      });
  4. Plain object: {[sid: string]: handler}

    fork({
      handlers: {
        [getMessageFx.sid]: (params) => ({ id: 0, text: "message" }),
        [getUserFx.sid]: async (params) => ({ name: "alice", age: 21 }),
      }
    });
    deprecation

    Such objects are deprecated since effector 23.0.0 and will be removed in future versions. Array of tuples is preferred.

Returns

Scope

Examples

Create two instances with independent counter state

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

Try it

Set initial state for store and change handler for effect

This is an example of test, which ensures that after a request to the server, the value of $friends is filled

import { createEffect, createStore, fork, allSettled } from "effector";

const fetchFriendsFx = createEffect<{ limit: number }, string[]>(async ({ limit }) => {
  /* some client-side data fetching */
  return [];
});
const $user = createStore("guest");
const $friends = createStore([]);

$friends.on(fetchFriendsFx.doneData, (_, result) => result);

const testScope = fork({
  values: [[$user, "alice"]],
  handlers: [[fetchFriendsFx, () => ["bob", "carol"]]],
});

/* trigger computations in scope and await all called effects */
await allSettled(fetchFriendsFx, {
  scope: testScope,
  params: { limit: 10 },
});

/* check value of store in scope */
console.log(testScope.getState($friends));
// => ['bob', 'carol']

Try it

Contributors