React - React.Component 存在的问题及优化(React.PureComponent 的使用)
react 官网:https://zh-hans.reactjs.org/docs/react-api.html#reactcomponent
一. React.Component 与 React.PureComponent
- React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现
shouldComponentUpdate()
,而 React.PureComponent 中以浅层对比prop
和state
的方式来实现了该函数。 - 如果赋予 React 组件相同的
props
和state
,render()
函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。 - React.PureComponent 中的
shouldComponentUpdate()
仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果。仅在你的props
和state
较为简单时,才使用 React.PureComponent,或者在深层数据结构发生变化时调用forceUpdate()
来确保组件被正确地更新。你也可以考虑使用immutable
对象加速嵌套数据的比较。 - 此外,React.PureComponent 中的
shouldComponentUpdate()
将跳过所有子组件树的prop
更新。因此,请确保所有子组件也都是“纯”的组件。
二. React.Component 存在的问题
- 两个问题:
- 只要执行
setState()
,即使不改变状态数据, 组件也会重新render()
。 - 只要当前组件重新
render()
, 就会自动重新render()
子组件,即使子组件没有用到父组件的任何数据。
- 只要执行
- 原因:
Component
中的shouldComponentUpdate()
总是返回true
- 解决思路:
只有当组件的
state
或props
数据发生改变时才重新render()
三. 解决(优化)方法
- 重写
shouldComponentUpdate()
方法比较新旧
state
或props
数据, 如果有变化才返回true
, 如果没有返回false
。shouldComponentUpdate(nextProps, nextState) { console.log(this.props, this.state); //当前的props和state console.log(nextProps, nextState); //将要变化的 目标props 和 目标state if ( JSON.stringify(this.state) === JSON.stringify(nextState) && JSON.stringify(this.props) === JSON.stringify(nextProps) ) { return false; } else { return true; } }
- 使用
React.PureComponent
import React, { PureComponent } from "react"; export default class index extends PureComponent { render() { return <div>index</div>; } }
四. 解决(优化)组件实例
this.setState()
真实修改、假修改 状态,对比render()
中是否会打印
-
重写
shouldComponentUpdate()
方法import React, { Component } from "react"; export default class Parent extends Component { state = { count: 10, }; shouldComponentUpdate(nextProps, nextState) { if ( JSON.stringify(this.state) === JSON.stringify(nextState) && JSON.stringify(this.props) === JSON.stringify(nextProps) ) { return false; } else { return true; } } increment = () => { // 假修改 this.setState({}); // 真实修改 // this.setState({ // count: this.state.count + 1, // }); }; render() { console.log("Parent_render"); //查看控制台是否打印 const { count } = this.state; return ( <div> <h2>Parent组件</h2> <span>数值为:{count}</span> <br /> <button onClick={this.increment}>+1</button> <Child count={count} /> </div> ); } } class Child extends Component { shouldComponentUpdate(nextProps, nextState) { if ( JSON.stringify(this.state) === JSON.stringify(nextState) && JSON.stringify(this.props) === JSON.stringify(nextProps) ) { return false; } else { return true; } } render() { console.log("child_render"); //查看控制台是否打印 const { count } = this.props; return ( <div> <h2>Child组件</h2> <span>Parent组件的数值是:{count}</span> </div> ); } }
-
使用
React.PureComponent
import React, { PureComponent } from "react"; export default class Parent extends PureComponent { state = { count: 10, }; increment = () => { // 假修改 this.setState({}); // 真实修改 // this.setState({ // count: this.state.count + 1, // }); }; render() { console.log("Parent_render"); //查看控制台是否打印 const { count } = this.state; return ( <div> <h2>Parent组件</h2> <span>数值为:{count}</span> <br /> <button onClick={this.increment}>+1</button> <Child count={count} /> </div> ); } } class Child extends PureComponent { render() { console.log("child_render"); //查看控制台是否打印 const { count } = this.props; return ( <div> <h2>Child组件</h2> <span>Parent组件的数值是:{count}</span> </div> ); } }