如何保留 React 组件的内容
介绍
当组件的状态或属性更新时,React 使用虚拟 DOM 重新渲染组件。这就是单页 React 应用如何根据用户交互为您带来动态内容而无需刷新页面的方式。但是,每次重新渲染组件时,应用程序都会失去一些性能优势。因此,需要通过跟踪更新的状态和属性来优化协调或更新 DOM的机制。
本指南重点介绍如何使用纯组件优化 React 应用程序的性能,并最终控制组件的重新渲染以保持组件的内容不变。
使用 Pure Componentst
纯组件是 React 中的特殊组件,仅当使用生命周期方法shouldComponentUpdate()和componentDidUpdate()隐式更改状态或属性时才会渲染。看看 React 中的以下代码,它每秒更新一次状态:
import React from 'react';
export default class Counter extends React.Component{
constructor(){
super();
this.state={
count: 0
}
this.componentDidUpdate=()=>{
console.log('rendered')
}
setInterval(()=>{
this.setState({
count: 0
})
},1000)
}
render(){
return(
<div>
<h2>Counter value: {this.state.count}</h2>
</div>
)
}
}
上述类组件的状态中计数初始化为0,并每秒将计数更新为相同值。状态已更新,但其值不变。然而,每次调用setState时,应用程序都会重新渲染,从而递归地陷入重新渲染的无限循环。
为了解决这个问题,您可以使用纯组件,它将先前的状态值与更新后的状态值进行比较,并决定组件是否应重新渲染。要打破上述代码中的无限重新渲染循环,只需在创建组件时添加关键字Pure即可。
export default class Counter extends React.PureComponent{
...
}
现在组件只会挂载而不会重新渲染。纯组件确实解决了不必要的重新渲染的问题,但并非完全如此。它们对前一个状态或props与下一个状态或props进行了浅层比较。这意味着 React 无法完全理解状态或props是否真的发生了变化,并且仍然可能导致一些不必要的重新渲染。
明确使用 shouldComponentUpdate()
您可以使用名为shouldComponentUpdate()的生命周期方法完全控制组件的重新渲染条件。它可以分别访问nextProps和nextState作为第一个和第二个参数,并根据是否决定重新渲染组件返回布尔值。您可以编写自己的函数来对两个对象进行深度比较并在此方法中调用它,也可以直接在其中执行深度比较。使用shouldComponentUpdate()扩展上述示例:
import React from 'react';
export default class Counter extends React.Component{
constructor(){
super();
this.state={
count: 0
}
this.componentDidUpdate=()=>{
console.log('rendered')
}
this.shouldComponentUpdate=(nextProps,nextState)=>{
return nextState.count!=this.state.count
}
setInterval(()=>{
this.setState({
count: 0
})
},1000)
}
render(){
return(
<div>
<h2>Counter value: {this.state.count}</h2>
</div>
)
}
}
由于对nextState和当前状态进行了深度比较,因此组件现在不会渲染。除非你确定这是唯一的方法,否则 React 不建议使用此方法。
纯组件的 Hooks 实现
以前,你无法在无状态函数组件中进行性能优化,因为纯组件必须始终是类组件。现在,你可以使用名为memo的高阶组件在函数组件中实现纯组件。术语memo源自术语memoization,后者是一种将计算结果存储在某处并在重复相同计算时返回这些结果的技术。在底层,当你第二次访问某个网站时,浏览器的缓存会更快地加载该网站的资源,从而实现记忆化。React.memo是一个高阶组件,它告诉函数组件仅在props发生变化时重新渲染,本质上使其成为一个纯组件。
考虑以下高阶组件,该组件每秒向子组件返回一个随机颜色。子组件利用此随机颜色来设置h1标签的样式。由于您经常从一组固定值中生成随机值,因此可能会遇到以前计算的值。换句话说,您的随机颜色可能会重复。这是记忆化的经典示例。要使用memo ,请将您的函数组件包装在对React.memo的调用中,React 将使用最后渲染的结果跳过渲染组件。考虑以下代码:
import React,{memo} from 'react';
const Name = memo(({ color}) => <>
<h1 style={{color:`${color}`}}>Hello Campers! How you doing?</h1>
</>);
export default class ColorsHOC extends React.Component {
colors = ["Red", "Green", "Blue"];
state = { color: '' };
componentDidMount() {
setInterval(() => {
const color = this.getRandomColor();
this.setState({ color});
}, 1000);
}
getRandomColor = () =>
this.colors[Math.floor(Math.random() * this.colors.length)];
render() {
return <Name color={this.state.color} />;
}
}
请记住,React.memo仅检查prop更改,而不检查state更改。在React.memo中使用useContext或useState仍会导致您的函数组件在 state 更改时进行渲染。
默认情况下,React.memo仅对props对象进行浅层比较。你可以传递自定义比较函数作为第二个参数,如下所示:
function MyComponent(props) {
}
function areEqual(prevProps, nextProps) {
//compare here
}
export default React.memo(MyComponent, areEqual);
结论
不应经常重新渲染的组件应设为纯组件,以减少不必要的渲染。通过本指南中讨论的方法,您可以忽略组件层次结构的子树,从而为您的应用带来显著的性能优势。但是,使用它们时要小心,因为不当使用可能会导致您的应用出现错误。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~