【问题标题】:Location of stateful component in the VDOM after re-render重新渲染后有状态组件在 VDOM 中的位置
【发布时间】:2017-10-27 12:26:40
【问题描述】:

如果一个有状态的反应组件C在时间T在VDOMV中的位置PT

然后

在重新渲染后T+1 时间V' 中的C 会在哪里?

例如在this fiddle 中,当父道具从true 更改为false 时,第一个有状态组件的状态被“转移”到第二个有状态组件。切换回来时,第二个组件的状态也会丢失。这怎么解释?记录这种行为的规则是否在某处可用? Here描述的不是很准确。

【问题讨论】:

    标签: reactjs virtual-dom


    【解决方案1】:

    你有一个像这样呈现的视图。

    <MyComponent />
    

    现在,如果要多次重新渲染此视图(导致相同的状态/生命周期,或者您所说的转移,这不是我会使用的词,每次渲染之间),则以下条件为真。

    • 此渲染树中的组件类型(标签名称:&lt;MyComponent /&gt;)是否与最后一个相同?
    • 组件是否与上次在同一个地方,相同的父级等?
    • 如果组件在上一次渲染中分配了一个键属性,它是否在与上次相同的父级下的下一个渲染树中,具有相同的键值?

    在下面的伪代码中想象一个完整的渲染树:

    <div id="awesome-container">
        <Parent>
            { randomBoolean ? <AlphaChild /> : <BetaChild /> }
        </Parent>
    </div>
    

    Alpha 和 Beta 组件在被另一个组件替换时将始终卸载,并且它们的状态将“重置”,也就是它们将作为新组件安装

    看上面的例子,你可能会认为这一切都是“未解析的 HTML”。自定义标签不是 DOM 中的最终产品。相反,解决后,它看起来更像这样:

    <div id="awesome-container"> // just an element, is stateless
        <div class="parent"> // has a lifecycle/state tied to it
             <span name="alpha"> // also has a lifecycle/state
                 <p>My job is to show the time: 10:00 AM</p>
             </span>
        </div>
    </div>
    

    如果AlphaChild 突然被BetaChild 取代,那么保留AlphaChild 状态/生命周期就没有意义了,对吧?如果我们确实想保留它,我们可能会保留一些数据,这些数据对于列表中的单纯子项来说太重要了(想到智能组件/父级或 Redux)。你也可以使用 CSS 隐藏组件,只是为了保留状态。

    如果我们没有键,我们将无法切换组件。

    constructor() {
    this.state = { components: [ <AlphaChild />, <BetaChild />, <CharlieChild /> ] };
    }
    
    someEvent() {
        // Moves the first element in the array to the last position.
        this.setState({ 
            this.state.components: [this.components.slice(1)].push(this.state.components[0]))
        }
    }
    
    render() {
        { this.state.components }
    }
    

    无论上述组件的顺序如何,例如:

    <BetaChild /> // has state
    <AlphaChild /> // has state
    <CharlieChild /> // has state
    

    状态将在每次重新排序组件之间被终止。

    <AlphaChild /> // has completely new state
    <CharlieChild /> // has completely new state
    <BetaChild /> // has completely new state
    

    这就是为什么键在反应中非常重要的原因,将状态保持在一个很可能被重新排序的列表中。

    没有什么比这更多的要跟踪了。如果组件从其父组件中移除并出现在代码中的其他位置,它将不会保持其旧状态/生命周期,因为它们是相同的远非显而易见。事实上,没有任何合乎逻辑的方式可以告诉我们情况是这样的。甚至没有键,因为键可以是渲染过程中任何多个列表的一部分。

    我希望这能让事情更清楚一点。如果您想了解有关虚拟 DOM 的更多信息,我建议您查看 Snabbdom on github。他们不会为您保留组件生命周期,因此您需要自己弄清楚。 Snabbmitt 可能有助于查看以激发灵感。

    不过,一般来说,我认为您不必费心阅读有关虚拟 DOM 的过多内容,只要遵循原则就可以了。

    【讨论】:

    • 哇,谢谢您的详细解答,我需要仔细阅读并花时间理解它。
    • 没问题!如果您在此评论区有其他问题,我会更新我的答案。准备好后,请将我的回答标记为已接受。谢谢!
    • 总而言之,组件可以通过两种方式保持其状态(身份):1)类型+到父级的树路径+兄弟之间的位置在重新渲染之间是相同的,2)类型+在重新渲染中,父级 + 键值的树路径相同(兄弟级之间的位置可以改变)。因此,如果组件有相同的键、相同的路径、相同的类型,那么无论兄弟姐妹如何更改/重新排序,它都会保持其状态?
    猜你喜欢
    • 2019-09-16
    • 2023-03-09
    • 1970-01-01
    • 2021-06-11
    • 2019-11-09
    • 1970-01-01
    • 2022-06-30
    • 2019-02-18
    • 2019-06-17
    相关资源
    最近更新 更多