[xstate] machine간에 부모 - 자식 관계 (트리)로 state, event를 관리하는 방법
문제
모델을 xstate에 떨어뜨려 가면, 아무래도 machine을 분할해, 1개의 machine가 다른 machine를 관리해 전체로서의 state를 관리하고 싶은 것이 나온다. (예: one-to-many, many-to-many)
 해결 방법
부모 machine에 아이 machine을 갖게 한다
방법은
뿐이라고 생각한다.
context에 유지
interface Context{
  child: ActorRefFrom<typeof childMachine>
}
...
{
  states: {
    idle: {
      entry: ["setChild"] // どこでもどのタイミングでも問題ない
    }
  }
},
{
  actions: {
    setChild: assign((context, event) => ({...context, child: spawn(childMachine)}))
  }
})
포인트는
spawn 를 사용해, context에 두어 두는 것. context에 두기 때문에, context를 갱신할 때까지 계속 존재한다.주의점으로서는 assign할 때에
assign((context, event) => ({ ...context, child: spawn(...) }))
assign({
  child: (context, event) => spawn(...)
})
그렇지 않으면 정상 작동하지 않습니다.
assign({
  child: spawn(...) // ❌
})
이렇게 하면 에러도 아무것도 나오지 않고, 움직이지 않는다.

기계를 invoke
{
  states: {
    idle: {
      invoke: {
        id: "childMachineId",
        src: childMachine,
        onDone: { ... }
      }
    }
  }
}
invoke이므로, invoke된 state내에서만 존재하고 있다. 용도로는 통상의 invoke service로 해서는 복잡하고, machine에 떨어뜨려 버리는 편이 간결하게 정리되는 때에 편리.
events
부모로부터 아이에게 이벤트를 던지는 법
send를 사용한다. send는 일반적인 invoke service를 향해 event를 던지기도 하지만, 부모와 자식 관계가 있는 machine이면 부모로부터 아이에게 event를 던질 수도 있다.
event를 던질 때에는 아이가 context내에 들어 있다면 그 객체(또는 spawn시의 이름), invoke된 machine이면 그 ID를 지정해 줄 필요가 있다.
주의점으로서 action 안에서. 반드시
context.child.send(...)의 send를 통해 이벤트를 보내야합니다.context 내의 spawn된 machine의 경우
import { actions, ... } from "xstate" // actions.pureを使う場合
{
  on: {
    "SOME.EVENT": {
      actions: [send("EVENT.TO.CHILD", { to: (context, event) => context.child })]
//    もしくは
//    actions: [send("EVENT.TO.CHILD", { to: ”spawned-child” })]
//    またはこうやっても良い
//    actions: ["sendToChild"]
    }
  }
},
{
  actions: {
    setChild: assign((context, event) => ({
      ...context, 
      child: spawn(childMachine, { name: "spawned-child" }) 
      // nameは指定できるが、contextからオブジェクト自体を参照できるのでしなくても問題ない
    })),
    sendToChild: actions.pure((context, event) => {
      // context, eventによって振り分けが必要だったり、
      // コードが煩雑になる場合はこういう風にactionに落とし込んだほうがスッキリする
      return send("EVENT.TO.CHILD", { to: context.child })
    })
  }
}
invoke된 machine의 경우
{
  on: {
    "SOME.EVENT": {
      // ここではidを直接指定する以外ない
      actions: [send("EVENT.TO.CHILD", { to: "childMachineId" })]
    }
  },
  states: {
    idle: {
      invoke: {
        id: "childMachineId",
        src: childMachine,
        onDone: { ... }
      }
    }
  }
}
복수의 아이 machine에 send 하고 싶은 경우
import { send } from "xstate" 에 쓰려고 하면 쓸 수 없지만 코드가 번잡하기 때문에 actions: [...] 를 사용한다.각 child에 대해 send를 생성하고 그것을 배열로 반환합니다.
import { actions, ... } from "xstate"
{
  context: {
    childMachines: []
  },
  on: {
    "ADD.CHILD": {
      actions: ["addChild"]
    }
    "EVENT.TO.CHILD_MACHINES": {
      actions: ["sendToChildren"]
    }
  },
},
{
  actions: {
    sendToChildren: actions.pure((context, event) => {
      return context.childMachines.map((child) => send("EVENT.TO.CHILD", { to: child }))
    })
  }
}
아이로부터 부모에게 event를 던질 경우
import { sendParent, ... } from "xstate"
{
  on: {
    "SOME.EVENT": {
      actions: [sendParent("EVENT.TO.PARENT")]
    }
  }
}
spawn의 sync와 autoForward

sync
부모로부터 아이를 spawn 할 때, 아이의 state 가 변경할 때마다 부모에게 통지를 하는지 어떤지. 아이의 상태가 A에서 B로 바뀌면 부모
actions.pure가 반응합니다. (아마 parentService.onTransition((state) => ...) 음)이것이라고 반응이 너무 많다고 하는 경우는, sync는 사용하지 않고 sendUpdate를 아이의 요소요소로 사용하면, 정확하게 부모에게 통지를 할 수 있다.
아이
{
  ...
  states: {
    idle: {},
    stateA: {
      entry: [sendUpdate()]
    },
  }
}
autoForward
는 부모로 받은 event를 그대로 아이에게도 흘릴지 어떨지. click 이벤트의 이벤트 버블링적인.
부모와 자식 관계가 좀처럼 꿀이 아닌 한은 사용하지 않는 것.
참고
invoke한 machine에서의 부모와 자식 관계 htps : // 기주 b. 코 m / m r r / ゔ ぃ에서 어쨌든 s / t ree / 마이 / src / 마을 s 에 machine이 있습니다.
매우 간단하게 만든 샘플.
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여([xstate] machine간에 부모 - 자식 관계 (트리)로 state, event를 관리하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/github0013@github/items/a7a2ea525f59f1e07e3e
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                 우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            
Reference
이 문제에 관하여([xstate] machine간에 부모 - 자식 관계 (트리)로 state, event를 관리하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/github0013@github/items/a7a2ea525f59f1e07e3e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)