原文链接:https://ssshooter.com/2019-03…我曾经对 shouldComponentUpdate 的用途不解。react 的卖点之一,是通过 diff 虚拟节点树,减少对真实节点的操作,所以我以前以为既然 diff 了,那就自然知道节点有没有更新了,diff 是根据 setState 的内容进行的,那 shouldComponentUpdate 有什么用呢?然而我以前的理解是完全错误的,造成这个疑问的原因便是对 React 渲染流程的不熟悉。从头说起。setState你修改了数据,需要 React 重新渲染页面,让你的新数据展示在页面上,需要借助 setState 方法。setState 调用后,组件的 render 方法也会自动调用,这就是为什么你能在页面看到新数据。但是无论你 setState 修改的是什么,哪怕是页面里没有的一个数据,render 都会被触发,并且父组件渲染中会嵌套渲染自组件。class Nest extends React.Component { render() { console.log(‘inner’) return <div>Nest</div> }}class App extends React.Component { render() { console.log(‘outer’) return ( <div> <button onClick={() => { this.setState({ anything: 1, }) }} > setState </button> <Nest /> </div> ) }}所以在这个例子中,点击按钮,即使修改的 anything 根本没有出现,甚至没有定义,render 函数还是如期运行。每次点击按钮,上面的代码会先输出 outer,然后输出 inner。renderrender 生成的是什么呢?一般来说大家都是写 jsx,所以视觉上是一个“dom”,但是实际上,官网也在显眼的位置告诉你,这其实是一个函数。// jsxconst element = <h1 className=“greeting”>Hello, world!</h1>// babel 转换为浏览器能运行的函数const element = React.createElement( ‘h1’, { className: ‘greeting’ }, ‘Hello, world!’)而因为 React 的组件层层嵌套,render 函数会生成一棵描述应用结构的节点树,并保存在内存中。在下一次渲染时,新的树会被生成,接着就是对比两棵树。diff官方一点的定义应该称为 reconciliation,也就是 React 用来比较两棵节点树的算法,它确定树中的哪些部分需要被更新。在确定两棵树的区别后,会根据不同的地方对实际节点进行操作,这样你看到的界面终于在这一步得到了改变。当年 React 也就因为这个高效的 dom 操作方法得到追捧。shouldComponentUpdate终于说到 shouldComponentUpdate,他是一个组件的方法,用于拦截组件渲染。让我们用例子解释所谓“拦截渲染”。class Nest extends React.Component { shouldComponentUpdate = () => { // <—- 注意这里 return false } render() { console.log(‘inner’) return <div>Nest</div> }}class App extends React.Component { render() { console.log(‘outer’) return ( <div> <button onClick={() => { this.setState({ anything: 1, }) }} > setState </button> <Nest /> </div> ) }}跟之前的例子差不多,不过当我们在子组件添加 shouldComponentUpdate 后,再点击按钮,结果是 ————没错,子组件的渲染函数并没有调用,借助 shouldComponentUpdate 返回 false,成功拦截了子组件的渲染。当然一般不会这么做,因为永远返回 false 的话这个组件(当然因为渲染函数没有运行,所以包括其所有子组件都是不会更新的)就永远不会更新了。常用操作是,在 shouldComponentUpdate 判定该组件的 props 和 state 是否有变化,就像这样:class Nest extends React.Component { shouldComponentUpdate = (nextProps, nextState) => { return ( !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState) ) } render() { console.log(‘inner’) return <div>Nest</div> }}这样可以浅比较 props 和 state 是否有变化,至于为什么不深比较?因为那样效率可能会比直接全都运行 render 还低…因为上面的操作太常见,React 直接为我们提供了 PureComponent:class Nest extends React.PureComponent { render() { console.log(‘inner’) return <div>Nest</div> }}使用 PureComponent 的效果就与上面浅比较一样,并且省掉了 shouldComponentUpdate。什么时候用?PureComponent 能提高性能!所以直接用 PureComponent 代替所有 Component!这当然是错的。对于明知道不需要修改的组件,肯定直接返回 false。而可能你没想到,对于明知道需要修改的组件,也请不要使用 PureComponent。因为正如上面所说,PureComponent 需要进行两次浅比较,而浅比较也是要时间的,若是你明知道这个组件百分百要修改,何必浪费时间去对比呢?所以 PureComponent 请用在较少进行修改的组件上。总结总结一下以上内容,整个流程基本如下:本文部分存在个人理解,如果文中有不严谨的地方,请在评论区指出,谢谢大家的阅读。参考文献:https://reactjs.org/docs/faq-…https://reactjs.org/docs/opti...https://github.com/xitu/gold-...https://cdb.reacttraining.com