XState

XState > 親・子・兄弟Machine間での通信

Table of Content

XState > 親・子・兄弟Machine間での通信

親と子、親を通じて子から子へ伝える方法のメモ

https://xstate.js.org/docs/guides/communication.html#invoking-machines

https://codesandbox.io/s/parent-child-fetcing-nest-child-inter-forked-6o749?file=/src/parentMachine.js

first

子マシン1号

import { createMachine, sendParent } from "xstate";

export const childMachine1 = createMachine({
  id: "remote",
  initial: "offline",
  states: {
    offline: {
      on: {
        WAKE: "online"
      }
    },
    online: {
      after: {
        1000: {
          actions: sendParent("CHILD1.COMPLETE")
        }
      }
    }
  }
});

子マシン2号

import { createMachine, sendParent } from "xstate";

export const childMachine2 = createMachine({
  id: "remote2",
  initial: "offline",
  states: {
    offline: {
      on: {
        WAKE: "online"
      }
    },
    online: {
      actions: sendParent("CHILD2.COMPLETE", {
        delay: 2000
      })
    }
  }
});

親マシン

entryで子マシンを2つ作ってContextに保持します。

import { Machine, assign, spawn, send } from "xstate";
import { childMachine1 } from "./childMachine1";

export const parentMachine = Machine({
  id: "parent-machine",
  initial: "idle",
  context: {
    child1: null,
    child2: null,
    url: null
  },
  states: {
    idle: {
      entry: assign({
        child1: () => spawn(childMachine1)
      }),
      on: {
        "running.start": { target: "child1_run" }
      }
    },
    child1_run: {
      after: {
        1000: {
          actions: send({ type: "WAKE" }, { to: (context) => context.child1 })
        }
      },
      on: {
        "CHILD1.COMPLETE": { target: "child1_completed" }
      }
    },
    child1_completed: {
      always: { target: "final" }
    },
    final: {
      type: "final"
    }
  }
});

Messaging

親 → 子

参考:https://xstate.js.org/docs/guides/actors.html#quick-reference

親側

イベントを送信

{
  actions: send(
    { type: 'SOME_EVENT' },
    {
      to: (context) => context.someRef
    }
  );
}

データを含むイベントを送信

{
  actions: send(
    (context, event) => ({ ...event, type: 'SOME_EVENT' }), 
    {
      to: (context) => context.someRef
    }
  );
}

イベントと特定のデータを送信

{
  actions: send(
    { type: 'SOME_EVENT', data: someData },
    {
      to: (context) => context.someRef
    }
  );
}

子側

イベントを受信

SOME_EVENTでevent.dataを受信、fooへ遷移する。

fooState: {
  on: {
    SOME_EVENT: { target: foo },
  },
},

イベントと特定のデータを受信

SOME_EVENTでevent.dataを受信し、ContextのsomeDataへ保管した後、fooへ遷移する。

fooState: {
  on: {
    SOME_EVENT: {
      target: foo,
      actions: assign({
        someData: (context, event) => event.data,
      }),
    },
  },
},

子 → 親

子側

親へイベントを送信

{
  actions: sendParent({ type: 'ANOTHER_EVENT' });
}

親へイベントとデータを送信

{
  actions: sendParent((context, event) => ({
    ...context,
    type: 'ANOTHER_EVENT'
  }));
}
{
  actions: sendParent((context, event) => ({
    type: 'ANOTHER_EVENT', 
    {foo: data}
  }));
}

親側

イベントを受信

barState: {
...
  on: {
    COMPLETE: { target: "complete", }
  }
},

遅延

barState: {
...
  on: {
    COMPLETE: { target: "complete", { delay: 1000 }}
  }
},

へイベントとデータを受信

barState: {
  on: {
    COMPLETE: {
      actions: assign({
        todos: (_, event) => event.foo
      }),
      target: "complete"
    }
  }
},