Javascript 我可以在React中跨多个树共享一个组件实例吗?

Javascript 我可以在React中跨多个树共享一个组件实例吗?,javascript,reactjs,xstate,Javascript,Reactjs,Xstate,我一直在创建一个API来帮助管理React中的状态机 它由三个部分组成: :接收机器作为道具,并为更深层次的组件设置上下文以供使用 :接收两个道具:状态&子项,并且仅当该状态当前处于活动状态时才呈现其子项 :接收一些任意的道具(每个道具都是用于转换机器的事件),并将它们转换为转换回调,以传递给其子级(它不是元素,而是由道具类型确定的元素类型) 以下是正在发挥作用的视觉表现: 使用React的上下文API,我可以根据机器的状态灵活地打开/关闭React树中的节点。下面是一个示例代码片段,演示了这

我一直在创建一个API来帮助管理React中的状态机

它由三个部分组成:

  • :接收机器作为道具,并为更深层次的组件设置上下文以供使用
  • :接收两个道具:
    状态
    &
    子项
    ,并且仅当该状态当前处于活动状态时才呈现其子项
  • :接收一些任意的道具(每个道具都是用于转换机器的事件),并将它们转换为转换回调,以传递给其
    子级(它不是元素,而是由
    道具类型
    确定的
    元素类型
  • 以下是正在发挥作用的视觉表现:

    使用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>
      );
    
    使用我当前的API,在每个
    中呈现
    将导致
    在发生状态更改时重新装载(从而破坏与之相关的任何内部状态)。DOM节点本身也将被重新装载,这可能会重新触发类似于
    自动聚焦
    (例如)

    我希望有一种方法可以在不同的“视图”中共享相同的
    实例,这样就不会发生这种重新装载。这可能吗?如果没有,是否有适合此API的替代解决方案

    非常感谢您的帮助


    PS:如果问题标题不合适,请建议更改,以便更容易理解此问题。谢谢

    问题在于无论您是否处于正确的状态,
    状态视图
    实例中的组件始终是构建的

    因此,在表单示例中,始终有3个
    form
    实例,但一次仅渲染1个。如前所述,为了维护状态并防止重新装载,您只能有1个
    表单
    实例

    当您将一个条件组件(
    MyForm
    )传递到另一个组件(
    StateView
    )中时,应始终将其包装在函数中

    您的
    StateView
    类只有在正确的状态下才能创建
    MyForm
    实例

    现在一次只有一个实例(假设一次只匹配一个状态),但每个
    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
    实例,其中每个实例一次只匹配一个状态

    在我看来,你的处境是人为的。与重新安装相比,我看不出有任何合理的理由支持共享。顺便问一下,你所说的持久化的“内部状态”到底是什么意思?形成焦点?为什么在不同的状态下它应该保持不变?@hindmost我用一个代码片段更新了OP,这应该可以澄清您的问题。到目前为止,我能想到的最好的解决方案是将
    道具存储为“状态”,并让每个视图操作这些值,然后将其传递给单个
    组件。您是否可以尝试为每个
    MyForm
    提供相同的
    id
    ?不过可能不行
    <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>