首页 > 解决方案 > 如何防止 XState 节点在接收事件时重置其子并行状态?

问题描述

我正在探索 XState 世界并尝试重新创建本次演讲中提到的机器@davidkpiano

并且面临着正确进行过渡的问题。当我向父机器发送消息时,它会重置所有子机器。

例如:我希望机器在我一个接一个地触发CHANGEFOCUS事件后处于肮脏专注的状态。但是在发送FOCUS消息后,原始状态会重置回原始状态

我发现了这个问题,但是多个转换做同样的事情(正如它在问题本身中实际描述的那样)

另外,我不想将有关原始、聚焦和触摸状态的所有信息存储到 context 中,因为它不会像使用状态机那样安全。

下面的代码可复制粘贴到https://xstate.js.org/viz/

const createPristineMachineConfig = (inputName) => {
  return {
    id: `${inputName}.pristine`,
    initial: 'pristine',
    states: {
      pristine: {
        on: {
          [`${inputName}.CHANGE`]: 'dirty',
        },
      },
      dirty: {
        type: 'final',
      },
    },
  };
};

const createTouchedConfig = (inputName) => {
  return {
    id: `${inputName}.touched`,
    initial: 'untouched',
    states: {
      untouched: {
        on: {
          [`${inputName}.TOUCH`]: 'touched',
        },
      },
      touched: {
        type: 'final',
      },
    },
  };
};

const createFocusedMachineConfig = (inputName) => {
  return {
    id: `${inputName}.focused`,
    initial: 'blurred',
    states: {
      blurred: {
        on: {
          [`${inputName}.FOCUS`]: 'focused',
        },
      },
      focused: {
        on: {
          [`${inputName}.BLUR`]: 'blurred',
        },
      },
    },
  };
};

const createInputMachineConfig = (inputName) => ({
  id: inputName,
  type: 'parallel',
  context: {
    value: '',
  },
  on: {
    FOCUS: {
      actions: send(`${inputName}.FOCUS`),
      internal: true,
    },
    BLUR: {
      actions: [send(`${inputName}.TOUCH`), send(`${inputName}.BLUR`)],
      internal: true,
    },
    CHANGE: {
      actions: [assign((ctx, event) => ({ ...ctx, value: event.payload.value })), send(`${inputName}.CHANGE`)],
      internal: true,
    },
  },
  states: {
    pristine: createPristineMachineConfig(inputName),
    touched: createTouchedConfig(inputName),
    focused: createFocusedMachineConfig(inputName),
  },
});

const loginInputMachine = Machine(createInputMachineConfig('login'));

标签: javascriptstate-machinestate-managementxstate

解决方案


也许这是因为dirty是最终状态,例如:

{
  id: 'loginForm',
  initial: 'idle',
  context: {
    error: undefined,
  },
  invoke: [
    {
      id: 'usernameInput',
      src: inputMachine,
    },
    {
      id: 'passwordInput',
      src: inputMachine,
    },
    {
      id: 'loginButton',
      src: buttonMachine,
    },
  ],
  states: {
    idle: {
    },
    processing: {

    },
    finished: {
    },
    failed: {
    },
  },
};

我有这台产生一些演员的机器,我可以通过loginForm以下方式通过机器访问loginForm.state.children.usernamInput,但如果其中一台机器达到最终状态,它会返回未定义。


推荐阅读