我一直在创建一个 API 来帮助管理 React 中的状态机。
它由三个组件组成:
<StateMachine>
:接收xstate
机器作为道具,并设置上下文供更深的组件使用。<StateView>
: 接收两个道具:state
&children
,并且仅当该状态当前处于活动状态时才呈现其子级。<StateControl>
: 接收一些任意的 props - 每个都是用于转换机器的事件 - 并将它们转换为转换回调以传递给它children
(这不是一个元素,而是由elementType
确定的PropTypes
)。
以下是正在发生的事情的视觉表示:
使用 React 的 context API,我可以根据机器的状态灵活地打开/关闭 React 树中的节点。这是一个示例代码片段,演示了这一点:
const MyMachine = () =>
{
return (
<StateMachine machine={sampleMachine}>
<StateView state="initializing">
<StateControl onSuccess="success">
{MySampleInitializer}
</StateControl>
</StateView>
<StateView state="initialized">
<p>{"App initialized"}</p>
</StateView>
</StateMachine>
);
这很好用!当机器处于“初始化”状态时,MySampleInitializer
被渲染。初始化完成后,onSuccess
调用将机器转换为“已初始化”。在这一点上,<p>
得到渲染。
现在的问题:
在大多数情况下,每个“状态视图”都会呈现不同的组件(当适当的状态变为活动状态时,它会被创建和安装)。
但是,如果我们只想将机器应用于单个组件怎么办?例如,我有一个<Form>
组件处理某些表单元素的渲染,并且应该根据表单当前所处的状态接收不同的道具。
const MyFormMachine = () =>
{
return (
<StateMachine machine={formMachine}>
<StateView state="unfilled">
<StateControl onFill="filled">
{(props) => <MyForm {...props} disableSubmit/>}
</StateControl>
</StateView>
<StateView state="filled">
<StateControl onClear="unfilled" onSubmit="submit">
{(props) => <MyForm {...props}/>}
</StateControl>
</StateView>
<StateView state="submitting">
<MyForm disableInput disableSubmit showSpinner/>
</StateView>
</StateMachine>
);
使用我当前的 API,<MyForm>
在每个中渲染 a<StateView>
将导致<MyForm>
在状态更改发生时重新安装(从而破坏与之关联的任何内部状态)。DOM 节点本身也将被重新挂载,这可能会重新触发autofocus
(例如)之类的事情。
我希望可能有一种方法可以<MyForm>
在各种“视图”中共享相同的实例,这样就不会发生这种重新安装。这可能吗?如果没有,是否有适合此 API 的替代解决方案?
非常感谢任何帮助。
PS:如果问题标题不合适,请提出更改建议,以便更容易理解这个问题。谢谢