问题描述
我正在开发一个 UI 项目,该项目通过共享上下文处理状态更新,非常类似于 here
const {appState,dispatch} = useContext(AppContext);
我不会通过 xstate 来处理某些组件的状态机。
const SomeComponent = () => {
const {appState,dispatch} = useContext(AppContext);
const [state,send,service] = useMachine(MyComponentStateMachine);
}
现在,理想情况下,我希望我的状态机在进入状态时分派某些事件。但是,状态机获取我的 AppContext 的最佳方式是什么?
目前,我正在组件本身上处理这个事件调度,观察状态机的状态并在它进入某个状态时根据需要调度一个事件:
const SomeComponent = () => {
const {appState,service] = useMachine(MyComponentStateMachine);
useEffect(() => service.subscribe(state => {
if(state.value == "Some relevant state of MyComponentStateMachine")
dispatch({type: SomeEvent,arg: 12345});
}).unsubscribe,[service]);
}
这很管用,但我觉得它的设计很糟糕。我认为直接从状态机而不是从组件调度这个事件会更清晰。
简单地为状态机创建一个工厂方法,将 dispatch 作为参数并保留它是否明智?
解决方法
我相信在那里调用你的调度函数没有错。由于您正在使用上下文,您将无法在机器内部调用调度,除非您将该函数作为参数传递。你可以试试,不知道行不行。
(您可以使用操作来触发事件或状态变化的副作用)
在那种情况下,它会是这样的:
<pre>
//Component
const SomeComponent = () => {
const { appState,dispatch } = useContext(AppContext);
const [ state,send ] = useMachine(MyComponentStateMachine);
useEffect(() => {
if(state.matches("stateName")) {
const data = { type: SomeEvent,arg: 12345 };
send("EVENT_NAME",{ callback: dispatch,data })
}
},[state]);
}
//Machine
const MyComponentStateMachine = Machine({
...
states: {
stateName: {
on: {
EVENT_NAME: "secondState",},secondState: {
entry: ["actionName"]
}
},{
actions: {
actionName: (ctx,e) => {
e.callback(e.data);
},}
}
});
</pre>
*** 另外看看我是如何比较状态的,这是一种更清晰的读取状态值的方法。此外,如果您已经在使用 useMachine 钩子,则无需订阅该服务,如果状态发生变化,该钩子将触发组件重新渲染。