DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 967,911 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Park Je Hoon
Park Je Hoon

Posted on

XState (2)

1νŽΈμ— μ΄μ–΄μ„œ..


States

state.hasTag

state에 tagλ₯Ό κ΄€λ¦¬ν•˜κ²Œ ν•  수 μžˆλ‹€. μ•„λž˜μ˜ μ½”λ“œμ™€ 같이 greenκ³Ό yellowκ°€ λ™μΌν•œ μƒνƒœλ‘œμ„œ λ§€μΉ­λœλ‹€λ©΄ 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')
Enter fullscreen mode Exit fullscreen mode

Persisting State

State κ°μ²΄λŠ” string json format으둜 μ§λ ¬ν™”ν•˜μ—¬ localstorage λ“±μ˜ κ°’μœΌλ‘œ λΆ€ν„° μ΄ˆκΈ°ν™” 될 수 μžˆλ‹€.

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);
Enter fullscreen mode Exit fullscreen mode

React와 μ‚¬μš©ν• λ• μ–΄λ–»κ²Œ μ‚¬μš©ν• κΉŒ ν•˜κ³  λ³΄λ‹ˆ @xstate/reactμ—μ„œλŠ” μ•„λž˜μ™€ 같이 κ°„λ‹¨ν•˜κ²Œ μ“°κ³  μžˆλ‹€.

// ...

// 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 (/* ... */)
}
Enter fullscreen mode Exit fullscreen mode

State Meta Data

state node의 κ΄€λ ¨ 속성을 μ„€λͺ…ν•˜λŠ” 정적 데이터인 메타 λ°μ΄ν„°λŠ” meta 속성에 지정할 수 μžˆλ‹€.

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' } }
Enter fullscreen mode Exit fullscreen mode

(κ³΅μ‹λ¬Έμ„œ 보고 {'yellow': { message: 'will be red' }}λ₯Ό κΈ°λŒ€ν–ˆμ—ˆλŠ”λ°..)

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.',
  }
}
*/
Enter fullscreen mode Exit fullscreen mode

State Node

state machine은 전체 μƒνƒœ(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...'
  }
}
Enter fullscreen mode Exit fullscreen mode

전체 StateλŠ” machine.transition()의 리턴 κ°’μ΄λ‚˜ service.onTransition()의 콜백 κ°’μ—μ„œλ„ μžˆλ‹€.

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

Enter fullscreen mode Exit fullscreen mode

XStateμ—μ„œ μƒνƒœ λ…Έλ“œλŠ” state configuration으둜 μ§€μ •λœλ‹€. 이듀은 machines의 states property에 μ •μ˜λ˜μ–΄μžˆλ‹€. ν•˜μœ„ μƒνƒœ(sub-state) λ…Έλ“œ μ—­μ‹œ λ§ˆμ°¬κ°€μ§€λ‘œ 계측 κ΅¬μ‘°λ‘œμ„œ states property의 μƒνƒœ λ…Έλ“œμ— 선언될 수 μžˆλ‹€. 'machine.transition(state, event)'μ—μ„œ κ²°μ •λœ μƒνƒœλŠ” μƒνƒœ λ…Έλ“œμ˜ 쑰합을 λ‚˜νƒ€λ‚Έλ‹€. 예λ₯Όλ“€μ–΄ μ•„λž˜μ˜ success와 ν•˜μœ„ μƒνƒœ itemsλŠ” { success: 'items' }둜 ν‘œν˜„λœλ‹€.

const fetchMachine = createMachine({
  id: 'fetch',
  // 이것도 States 이고
  states: {
    success: {
      // μžμ‹ μƒνƒœλ₯Ό μ΄ˆκΈ°ν™” ν•˜κ³ 
      initial: { target: 'items' },

      // μžμ‹ μƒνƒœμž„.
      states: {
        items: {
          on: {
            'ITEM.CLICK': { target: 'item' }
          }
        },
        item: {
          on: {
            BACK: { target: 'items' }
          }
        }
      }
    },
  });

Enter fullscreen mode Exit fullscreen mode

μƒνƒœ λ…Έλ“œμ˜ μœ ν˜•

μƒνƒœ λ…Έλ“œλŠ” 5가지가 μžˆλ‹€.

  • atomic - μžμ‹ μƒνƒœκ°€ μ—†λŠ” λ…Έλ“œ (leaf node)
  • compound - ν•˜λ‚˜ μ΄μƒμ˜ μƒνƒœλ₯Ό ν¬ν•¨ν•˜λ©° 이런 ν•˜μœ„ μƒνƒœ 쀑 ν•˜λ‚˜κ°€ 킀인 intial μƒνƒœκ°€ μžˆλ‹€.
  • parallel - 2개 μ΄μƒμ˜ ν•˜μœ„ μƒνƒœλ₯Ό ν¬ν•¨ν•˜λ©° λ™μ‹œμ— λͺ¨λ“  ν•˜μœ„ μƒνƒœκ°€ μžˆλ‹€λŠ” 것을 λ‚˜νƒ€λ‚΄κΈ° μœ„ν•¨μ΄μ–΄μ„œ μ΄ˆκΈ°μƒνƒœκ°€ μ—†λ‹€. (μ•½κ°„μ˜ μ˜μ—­μΈλ° μ΄λ ‡κ²Œ μ΄ν•΄ν–ˆμŒ..)
  • final - μΆ”μƒμ μœΌλ‘œ "말단" μƒνƒœμž„μ„ λ‚˜νƒ€λ‚΄λŠ” 단말 λ…Έλ“œμ΄λ‹€.
  • history - λΆ€λͺ¨ λ…Έλ“œμ˜ κ°€μž₯ 졜근의 shallow or deep history μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 좔상 λ…Έλ“œ

μ•„λž˜ μ„ μ–ΈλΆ€λ₯Ό λ³΄λ‹ˆκΉŒ 쑰금 더 이해가 λ˜μ—ˆλ‹€.

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'
        }
      }
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

μœ ν˜•μ„ λͺ…μ‹œμ μœΌλ‘œ μ§€μ •ν•˜λ©΄ typescript 뢄석 및 μœ ν˜•κ²€μ‚¬ κ΄€λ ¨μœΌλ‘œ μœ μš©ν•˜λ‹€κ³  ν•˜λŠ”λ°, parallel, history, final만 ν•΄λ‹Ήλœλ‹€.


이후 3νŽΈμ—μ„œ Transient State Nodes λΆ€ν„° μ΄μ–΄μ„œ 진행 μ˜ˆμ •μž…λ‹ˆλ‹€.

Top comments (0)

Update Your DEV Experience Level:

Settings

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. πŸ›