反应:防止在父级重新渲染时重新挂载

React: Prevent remount when parent rerenders

本文关键字:新渲染 新挂载 反应      更新时间:2023-09-26

我有一个组件,Split,它需要两个孩子。第一个孩子将显示在屏幕的左侧,第二个孩子将显示在右侧。如果屏幕宽度低于某个点,则仅显示右侧,左侧将从DOM中删除。

示例子项可以是Sidebar组件和Content组件。对于移动设备,我不想显示菜单,但有一个特殊的移动菜单,我弹出。

我的问题是:如何在不卸载和重新安装Content组件的情况下卸下Sidebar组件?

我的Content组件在componentDidMount上获取数据,我不希望它再次重新获取或重新挂载(从而丢弃用户输入(。

基本上我有这样的东西:

<Split>
  <Sidebar/>
  <Content/>
</Split>

Split 的渲染方法看起来像这样:

let children;
let firstChild = this.props.children[0];
let lastChild = this.props.children.pop();
if (this.state.responsive === 'singleColumn') {
  children = (
    <div>
      <div style={{display: 'none'}}>{firstChild}</div>
      {lastChild}
    </div>
  );
} else {
  children = (
    <div>
      {firstChild}
      {lastChild}
    </div>
  );
}
return (
  <div>
    {children}
  </div>
);

即使 {lastChild} 总是被渲染,但无论如何,每次拆分必须重新渲染时,它仍然会被卸载并重新挂载!

甚至有一个看起来像这样的渲染:

return (
  <div>
    {this.props.children.pop()}
  </div>
);

导致最后一个子项(永不更改(在渲染之前被卸载并重新挂载。

如果我改为修改Split并将始终存在于 DOM 中的组件作为属性传递,如下所示:

<Split staticComponent={<Content />}>
  <Sidebar />
</Split>

它工作正常。那为什么当我只是像这样弹出最后一个孩子时它不起作用{this.props.children.pop()}而不是这个{this.props.staticComponent}

有没有理智的方法可以解决这个问题?

终于设法解决了这个问题!我重写了Split的渲染,看起来像这样:

let left;
if (this.state.responsive !== 'singleColumn') {
  left = this.props.children.slice(0, -1);
}
return (
  <div ref="split" className={classes.join(' ')}>
    {left}
    {this.props.children[this.props.children.length-1]}
  </div>
);

这样,最后一个孩子总是被渲染。显然pop()不起作用,因为后来我修改了触发奇怪行为的原始子数组。

这可以通过生命周期方法完成:shouldComponentUpdate:

shouldComponentUpdate: function(nextProps, nextState) {
  return this.props.value !== nextProps.value;
}

如果内部逻辑返回 false,则组件将不会更新。

查看文档:https://facebook.github.io/react/docs/advanced-performance.html

您可以在组件的生命周期中使用 shouldComponentUpdate 函数。 如果它返回 false,则根据文档

如果 shouldComponentUpdate 返回 false,则 render(( 将被完全跳过,直到下一个状态发生变化。此外,不会调用 componentWillUpdate 和 componentDidUpdate。