Xステート (2)


에 이어서..




state.hashTag



state에 tag를 관리하게 할 수 있다. 아래의 코드와 같이 greenyellow 가 동일한 상태로서 매칭된다면 state.matches('green') || state.matchs('yellow') 대신 사용할 수 있다.

const machine = createMachine({
  initial: 'green',
  states: {
    green: {
      tags: 'go' // single tag
    },
    yellow: {
      tags: 'go'
    },
    red: {
      tags: ['stop', 'other'] // multiple tags
    }
  }
});

const canGo = state.hasTag('go');
// === state.matches('green') || state.matchs('yellow')


持続状態



.

const jsonState = JSON.stringify(currentState);

// 어딘가에서 저장하고..
try {
  localStorage.setItem('app-state', jsonState);
} catch (e) {
  // unable to save to localStorage
}

// ...

const stateDefinition =
  JSON.parse(localStorage.getItem('app-state')) || myMachine.initialState;

// State.create()를 이용하여 plain object로 부터 스토어를 복구시킴
const previousState = State.create(stateDefinition);

// machine.resolveState()를 이용하여 새 상태로 정의됨
const resolvedState = myMachine.resolveState(previousState);


React は State に登録されています.

// ...

// Get the persisted state config object from somewhere, e.g. localStorage
const persistedState = JSON.parse(localStorage.getItem('some-persisted-state-key')) || someMachine.initialState;

const App = () => {
  const [state, send] = useMachine(someMachine, {
    state: persistedState // provide persisted state config object here
  });

  // state will initially be that persisted state, not the machine's initialState

  return (/* ... */)
}


状態メタデータ



状態ノードは、 @xstate/react の状態ノードです.

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      tags: 'go',
      meta: {
        message: 'can go',
      },
      on: { 'WILL_STOP': 'yellow' },
    },
    yellow: {
      tags: 'go',
      meta: {
        message: 'will be red',
      },
      on: { 'STOP': 'red' }
    },
    red: {
      tags: ['stop', 'other'],
      meta: {
        message: 'stop!',
      },
      on: { 'GO': 'green' }
    }
  }
});
const yellowState = lightMachine.transition('green', {
  type: 'WILL_STOP'
});

console.log(yellowState.meta);
// { 'light.yellow': { message: 'will be red' } }


(공식문서 보고 meta 를 기대했었는데..)

meta를 여러개 포함할때도 모두 표현해준다.

const fetchMachine = createMachine({
  id: 'fetch',
  // ... 중략
    loading: {
      after: {
        3000: 'failure.timeout'
      },
      on: {
        RESOLVE: { target: 'success' },
        REJECT: { target: 'failure' },
        TIMEOUT: { target: 'failure.timeout' } // manual timeout
      },
      meta: {
        message: 'Loading...'
      }
    },
    failure: {
      initial: 'rejection',
      states: {
        rejection: {
          meta: {
            message: 'The request failed.'
          }
        },
        timeout: {
          meta: {
            message: 'The request timed out.'
          }
        }
      },
      meta: {
        alert: 'Uh oh.'
      }
    },
  // ... 하략
});

const failureTimeoutState = fetchMachine.transition('loading', {
  type: 'TIMEOUT'
});
console.log(fetchMachine.meta)
/*
{
  "fetch.failure.timeout': {
    'message': 'The request timed out.',
  },
  'fetch.failure': {
    'alert": "Uh oh.',
  }
}
*/


状態ノード



ステート マシンは、全体的な状態 (overall state) であり、状態ノードはステート ノード (State Node) である. 아래의 상태 명세는 위 예제에서 가져왔다.

// 위의 fetchMachine의 loading 참고
// 해당 State의 configuration 내부의 config에서 확인 가능.
{
  'after': {
    '3000': 'failure.timeout'
  },
  'on': {
    'RESOLVE': {
      'target': 'success'
    },
    'REJECT': {
      'target': 'failure'
    },
    'TIMEOUT': {
      'target': 'failure.timeout'
    }
  },
  'meta': {
    'message': 'Loading...'
  }
}


전체 State는 {'yellow': { message: 'will be red' }} 의 리턴 값이나 machine.transition() 의 콜백 값에서도 있다.

const nextState = fetchMachine.transition('idle', { type: 'FETCH' });
// State {
//   value: 'loading',
//   actions: [],
//   context: undefined,
//   configuration: [ ... ]
//   ...
// }



XState は状態構成に含まれています.このマシンは service.onTransition() のプロパティです. 하위 상태(sub-state) 노드 역시 마찬가지로 계층 구조로서 states property 상태 노드에 선언될 수 있다. 'machine.transition(state, event)' は、次のようになります. 예를들어 아래의 states 와 하위 상태 successitems 로 표현된다.

const fetchMachine = createMachine({
  id: 'fetch',
  // 이것도 States 이고
  states: {
    success: {
      // 자식 상태를 초기화 하고
      initial: { target: 'items' },

      // 자식 상태임.
      states: {
        items: {
          on: {
            'ITEM.CLICK': { target: 'item' }
          }
        },
        item: {
          on: {
            BACK: { target: 'items' }
          }
        }
      }
    },
  });



상태 노드의 유형



상태 노드는 5가지가 있다.
  • { success: 'items' } - 자식 상태가 없는 노드 (リーフノード)
  • atomic - 하나 이상의 포함하며 이런 하위 상태 중 하나가 키인 compound 상태가 있다.
  • intial - 2개 이상의 하위 상태를 포함하며 동시에 모든 하위 상태가 있다는 것을 나타내기이 위함함이 위함다. 가. (약간의 의역인데 이렇게 이해했음..)
  • parallel - 추상적으로 "말단"상태임을 나타내는 단말 노드이다.
  • final - 부모 노드의 가장 최근의 浅い歴史または深い歴史

    아래 선언부를 보니까 조금 더 이해가 되었다.

    const machine = createMachine({
      id: 'fetch',
      initial: 'idle',
      states: {
        idle: {
          // 단일 노드
          type: 'atomic',
          on: {
            FETCH: { target: 'pending' }
          }
        },
        pending: {
          // resource1, resource2 두개가 parallel 하게 있구나..
          type: 'parallel',
          states: {
            resource1: {
              // 내부에 pending, success 두가지를 갖는 복합 상태
              type: 'compound',
              initial: 'pending',
              states: {
                pending: {
                  on: {
                    'FULFILL.resource1': { target: 'success' }
                  }
                },
                success: {
                  type: 'final'
                }
              }
            },
            resource2: {
              type: 'compound',
              initial: 'pending',
              states: {
                pending: {
                  on: {
                    'FULFILL.resource2': { target: 'success' }
                  }
                },
                success: {
                  type: 'final'
                }
              }
            }
          },
          // resource1, resource2 둘 다 final 상태가 되면 success로
          onDone: 'success'
        },
        success: {
          type: 'compound',
          initial: 'items',
          states: {
            items: {
              on: {
                'ITEM.CLICK': { target: 'item' }
              }
            },
            item: {
              on: {
                BACK: { target: 'items' }
              }
            },
            hist: {
              type: 'history',
              history: 'shallow'
            }
          }
        }
      }
    });
    


    유형을을명시적으로지정タイプスクリプト분석분석및유형검사으로으로유용、historyparallelhistory

    이후 3편에서 final 부터 이어서 진행 예정입니다.