我一直在创建一个API,以帮助管理React中的状态机。它包含三个组件:<StateMachine>:接收xstate机器作为道具,并设置上下文供更深层次的组件使用。<StateView>:接收两个道具:state和children,并且仅在该状态当前处于活动状态时才渲染其子级。<StateControl>:接收一些任意道具-每个道具都是用于转换机器的事件-并将其转换为转换回调以向下传递到其children(这不是元素,而是由)。这是正在播放的内容的视觉表示:使用React的上下文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> );这很棒!当计算机处于“正在初始化”状态时,将渲染elementType。初始化完成后,将调用PropTypes,它将机器转换为“已初始化”。此时,MySampleInitializer被渲染。现在的问题是:在大多数情况下,每个“状态视图”将呈现一个不同的组件(当适当的状态变为活动状态时将创建并安装该组件)。但是,如果我们只想将机器应用于单个组件怎么办?例如,我有一个onSuccess组件,它处理某些表单元素的呈现,并应根据表单当前所处的状态接收不同的支持。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,在每个<p>中呈现一个<Form>都会导致在状态更改发生时重新挂载<MyForm>(从而破坏与之关联的任何内部状态)。 DOM节点本身也将重新安装,这可能会重新触发诸如<StateView>之类的事情。我希望有一种方法可以在各种“视图”之间共享相同的<MyForm>实例,这样就不会发生这种重新安装。这可能吗?如果不是,是否有适合该API的替代解决方案?任何帮助,不胜感激。PS:如果问题标题不合适,请提出更改建议,以便可以更方便地访问此问题。谢谢 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 问题在于,无论您是否处于正确的状态,都始终构造StateView实例内部的组件。因此,在您的表单示例中,总是有3个Form实例,但一次仅渲染1个。如前所述,您只能有1个Form实例以维护状态并防止重新安装。将条件组件(MyForm)传递到另一个组件(StateView)时,应始终将其包装在函数中。如果您处于正确状态,则您的StateView类只能创建MyForm实例。现在,您一次只具有1个实例(假设一次仅匹配1个状态),但是每个StateView仍具有自己的实例,该实例不共享。据我所知,除非在同一个父组件中,否则您不能避免使用单独的实例。我将更改您的StateView组件以处理多个状态检查,而不是一个。这样,当状态更改时(再次假设一次仅匹配一种状态),实例将被重用。您的StateView构造可能如下所示:<StateMachine machine={formMachine}> <StateView> {{ "unfilled": () => ( <StateControl onFill="filled"> {(props) => <MyForm {...props} disableSubmit/>} </StateControl> ), "filled": () => ( <StateControl onClear="unfilled" onSubmit="submit"> {(props) => <MyForm {...props}/>} </StateControl> ), "submitting": () => ( <StateControl> {(props) => <MyForm disableInput disableSubmit showSpinner/>} </StateControl> ) }} </StateView></StateMachine>注意,为了重用组件,该组件必须是相同的类型。我将第三个MyForm包裹在一个空的StateControl中,以便每个状态都构造一个StateControl,因此可以重用这些组件。还要注意,如果在单个StateView中确实一次具有多个状态匹配,则可以为每个StateControl提供一个key属性。相同的key属性值不应在可能同时实例化的两个组件上使用。一个更简单的解决方案是只具有单独的StateView实例,其中每个实例一次仅匹配一个状态。 (adsbygoogle = window.adsbygoogle || []).push({});
09-20 11:05