0

我有一个多步骤表格,基本上有这些基本步骤:select services -> contact -> billing. 当用户更改他们所在的步骤时,我会显示一个进度条并发出事件,这是我当前使用 xstate 的基本模式:

const formMachine = new Machine({
  id: 'form-machine',
  initial: 'selectService',
  context: {
    progress: 0,
    pathname: '/select-service',
  },
  states: {
    selectService: {
      entry: assign({
        progress: 0,
        pathname: '/select-service',
      }),
      on: {
        NEXT: 'contact',
      }
    },
    contact: {
      entry: assign({
        progress: 1 / 3,
        pathname: '/billing'
      }),
      on: {
        PREVIOUS: 'selectService',
        NEXT: 'billing',
      }
    },
    // ... there's more actions but that's the gist of it
  }
});

这是可视化: 在此处输入图像描述

在我的反应组件中,我观察这个服务的变化,pathname所以我可以推送到历史记录

function SignupFormWizard() {
  const history = useHistory();
  const [state, send, service] = useMachine(formMachine);

  useEffect(() => {
    const subscription = service.subscribe((state) => {
      history.push(state.context.pathname);
    });
    return subscription.unsubscribe;
  }, [service, history]);

  // ...
}

但是,问题是:每当我重新访问一条路线(例如,我直接导航到/billing)时,它会立即将我带回/select-service. 这对我的代码来说是有意义的,因为初始状态和订阅会这样做。

我将如何在特定节点初始化状态机?

4

1 回答 1

4

useMachinehook 接受第二个参数,它是一个配置对象。在这个对象中,您可以使用state键设置状态,但您必须自己构造状态,它看起来像这样:

let createdState = State.create(stateDefinition);
let resolvedState = formMachine.resolve(state);
let [state, send, service] = useMachine(formMachine, {state: resolvedState});

在我看来,当您需要恢复持久状态时它工作得很好,但是stateDefinition从头开始手动创建太麻烦了。

您可以做的是创建初始状态并选择您想要实际开始的位置:

initial: {
  always: [
    {
      target: "selectService",
      cond: "isSelectServicePage",
    },
    {
      target: "contact",
      cons: "isContactPage",
    },
    {
      target: "billing",
      cond: "isBillingPage",
    },
  ],
}

然后,当您启动机器时,您所要做的就是设置初始上下文值:

let location = useLocation();
let [state, send, service] = useMachine(formMachine, {
  context: { pathname: location.pathname },
});
于 2021-03-20T11:08:37.267 回答