gpt4 book ai didi

javascript - React 在重新渲染父组件时如何重用子组件/保持子组件的状态?

转载 作者:行者123 更新时间:2023-12-03 14:37:23 24 4
gpt4 key购买 nike

在 React 中,每次渲染/重新渲染组件时,它都会使用 createElement 重新生成它的所有子节点/组件。 . React 如何知道何时在重新渲染之间保持组件状态?
例如,考虑以下代码:

class Timer extends Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
tick() {
this.setState(state => ({ seconds: state.seconds + 1 }));
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return createElement('div', null,
'Seconds: ',
this.state.seconds
);
}
}
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicks: 0 };
}
click() {
this.setState(state => ({ clicks: state.clicks + 1 }));
}
render() {
return createElement('button', { onClick: () => this.click() },
createElement(Timer, null),
'Clicks: ',
this.state.clicks
);
}
}
render(createElement(Button, null), document.getElementById('root'));
您可以使用 Preact REPL here 尝试此代码.
请注意,当按下按钮并更新 clicks 值时, Timer 的状态组件仍然存在并且不会被替换。 React 如何知道重用组件实例?
虽然一开始这似乎是一个简单的问题,但当您考虑更改传递给子组件的 Prop 或子组件列表等事情时,它会变得更加复杂。 React 如何处理更改子组件的 props?即使子组件的 Prop 发生了变化,它的状态是否仍然存在? (在 Vue 中,组件的状态会在其 props 更改时保持不变)列表怎么样?当子组件列表中间的条目被删除时会发生什么?对这样的列表进行更改显然会生成非常不同的 VDOM 节点,但组件的状态仍然存在。

最佳答案

createElement对比 render与安装
当一个 React 组件比如你的 Button渲染后,使用 createElement 创建了许多子级。 . createElement(Timer, props, children)不创建 Timer 的实例组件,甚至渲染它,它只创建一个“React 元素”,它表示应该渲染组件的事实。
当您的 Button被渲染,react will reconcile与前一个结果的结果,来决定每个子元素需要做什么:

  • 如果元素与先前结果中的元素不匹配,则创建一个组件实例,然后安装然后渲染(递归地应用相同的过程)。请注意,当 Button第一次渲染,所有的 child 都会是新的(因为没有以前的结果可以匹配)。
  • 如果元素与前一个结果中的一个匹配,则重用组件实例:更新其 props,然后重新渲染组件(再次递归地应用相同的过程)。如果 props 没有改变,React 甚至可能选择不重新渲染以提高效率。
  • 先前结果中与新结果中的元素不匹配的任何元素都将被卸载并销毁。

  • React 的 diffing 算法
    如果 React 比较它们并且它们具有相同的类型,则一个元素“匹配”另一个元素。
    React 比较子元素的默认方式是简单地同时遍历两个子元素列表,将第一个元素相互比较,然后是第二个元素,依此类推。
    如果 child 有 key s,然后将新列表中的每个 child 与旧列表中具有相同键的 child 进行比较。
    React Reconciliation Docs以获得更详细的解释。
    例子
    您的 Button总是只返回一个元素:a button .所以,当你的 Button重新渲染, button匹配,并且它的 DOM 元素被重用,那么 button 的子元素进行比较。
    第一个 child 总是一个 Timer ,所以类型匹配并且组件实例被重用。 Timer props 没有改变,所以 React 可能会重新渲染它(在具有相同状态的实例上调用 render),或者它可能不会重新渲染它,从而保持树的那部分保持不变。这两种情况都会在您的情况下产生相同的结果 - 因为您在 render 中没有副作用- React 故意将何时重新渲染的决定作为实现细节。
    第二个 child 总是字符串 "Clicks: "所以 react 也只留下了那个 DOM 元素。
    如果 this.state.click自上次渲染以来已经改变,那么第三个 child 将是一个不同的字符串,可能从 "0" 改变至 "1" ,因此文本节点将在 DOM 中被替换。

    如果 Button小号 render将返回一个不同类型的根元素,如下所示:
      render() {
    return createElement(this.state.clicks % 2 ? 'button' : 'a', { onClick: () => this.click() },
    createElement(Timer, null),
    'Clicks: ',
    this.state.clicks
    );
    }
    然后在第一步中, a将与 button 进行比较并且因为它们是不同的类型,旧元素及其所有子元素将从 DOM 中删除、卸载和销毁。然后新元素将在没有先前渲染结果的情况下创建,因此新的 Timer实例将以新状态创建,并且计时器将返回 0。


    Timer火柴?
    上一棵树
    新树


    不匹配 <div><Timer /></div> <span><Timer /></span>
    匹配 <div>a <Timer /> a</div> <div>b <Timer /> b</div>
    不匹配 <div><Timer /></div> <div>first <Timer /></div>
    匹配 <div>{false}<Timer /></div> <div>first <Timer /></div>
    匹配 <div><Timer key="t" /></div> <div>first <Timer key="t" /></div>

    关于javascript - React 在重新渲染父组件时如何重用子组件/保持子组件的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65463824/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com