javascript - 防止组件在 DOM 的不同部分显示时卸载
问题描述
我的应用程序的布局会根据用户做出的一些选择而改变,因此相同的组件会挂在 DOM 中的不同节点下。不幸的是,React 卸载并重新安装了组件。结果,我的组件丢失了已累积的状态。我试图添加一个key
属性来传达这是同一个实例的信息,但我得到了相同的结果。下面显然是一个SSCCE。每次用户单击按钮时,组件A
都会被卸载并重新安装:
class A extends React.Component {
componentWillUnmount = () => {
console.log('map::componentWillUnmount()');
}
componentDidMount = () => {
console.log('map::componentDidMount()');
}
render() {
return (
<div>
this is component A
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state={i:0};
}
increment = () => {
this.setState({i: this.state.i+1});
}
render() {
console.log('app::render');
if (this.state.i % 2 === 0)
return (
<>
<div>
<div>
<A key={42}/>
</div>
</div>
<button onClick={this.increment}>re-render</button>
</>
);
else return (
<>
<div>
<A key={42}/>
</div>
<button onClick={this.increment}>re-render</button>
</>
)
}
}
只是为了澄清一下,我的代码除了重现问题之外并没有试图实现任何目标,就像我说的那样,它是一个 SSCCE。当然,在某些应用程序中,用户可以从“首选项”菜单更改布局,以便组件根据用户的偏好最终位于 DOM 中的不同位置。我无法想象在这种情况下失去状态是可以接受的。处理这种情况的正确方法是什么?
解决方案
这是因为条件渲染返回两个不同的树结构,其中路径A
不同。
React.Fragment
>div
>div
>A
React.Fragment
>div
>A
想象一下,如果我们通过使用普通 JS 手动进行安装和卸载来模仿 React,我们将不得不:
- 存储
<A/>
为变量 - 移除内部
<div/>
(<A/>
也会自动移除) - 然后将先前存储的附加
<A/>
到外部<div/>
(这实际上也不是一个好方法,因为这假设<A/>
一旦安装它就永远不需要更新自身,即使道具发生变化)
只要有一个 remove 和 append,它就相当于一个 React 组件被卸载然后再次安装。
代码有点模糊,我无法通过在第一个条件下使用 2<div/>
秒而在第二个条件下只有 1来判断它试图实现的目标<div/>
。但也许您可以使用三元运算符有条件地呈现您需要的内容而无需<A/>
理会(并且可能需要一点 CSS 来使内部<div/>
看起来好像嵌套在另一个内部<div/>
)。这样,在更改状态<A/>
时不会卸载。<App/>
return (
<>
<div>
<A />
{condition ? // where `condition` is a boolean
<div style={{
position: 'absolute'
// and may be other styles to achieve the visual trickery
}}>
{/* your content here */}
</div>
:
null
}
</div>
<button onClick={this.increment}>re-render</button>
</>
)
顺便说一句,他们说 42 是一切的答案,但我认为不适用于这种情况。将密钥设置为 42 将无济于事。
推荐阅读
- typescript - 如何在谷歌云功能中使用 geofirex
- c++ - using 语句和受保护的构造函数
- woocommerce - 尝试使用创建的新客户字段获取运输字段
- java - My AWS Rekognition sample code doesn't run
- flutter - disappear of the text written in the text field after pressing done
- android - Why can't Android release the finished activity from memory after AsyncTask finishes?
- python-3.x - Linux 上的 python 中的 openCV 在显示图像时爆炸
- android - 是否可以包含相对于底部而不是顶部元素的按钮?
- c# - 不确定如何解决我的 System.NullReferenceException
- casting - 如何克隆 Rc 特征对象并将其转换为另一个特征对象?