资讯专栏INFORMATION COLUMN

React 渲染优化:diff 与 shouldComponentUpdate

chnmagnus / 2771人阅读

摘要:在下一次渲染时,新的树会被生成,接着就是对比两棵树。官方一点的定义应该称为,也就是用来比较两棵节点树的算法,它确定树中的哪些部分需要被更新。终于说到,他是一个组件的方法,用于拦截组件渲染。让我们用例子解释所谓拦截渲染。

原文链接: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 
Nest
} } class App extends React.Component { render() { console.log("outer") return (
) } }

所以在这个例子中,点击按钮,即使修改的 anything 根本没有出现,甚至没有定义,render 函数还是如期运行。每次点击按钮,上面的代码会先输出 outer,然后输出 inner。

render

render 生成的是什么呢?一般来说大家都是写 jsx,所以视觉上是一个“dom”,但是实际上,官网也在显眼的位置告诉你,这其实是一个函数。

// jsx
const element = 

Hello, world!

// 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 
Nest
} } class App extends React.Component { render() { console.log("outer") return (
) } }

跟之前的例子差不多,不过当我们在子组件添加 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 
Nest
} }

这样可以浅比较 props 和 state 是否有变化,至于为什么不深比较?因为那样效率可能会比直接全都运行 render 还低...

因为上面的操作太常见,React 直接为我们提供了 PureComponent:

class Nest extends React.PureComponent {
  render() {
    console.log("inner")
    return 
Nest
} }

使用 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...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109207.html

相关文章

  • React组件性能优化

    摘要:如果组件是纯函数的,就是给组件相同的和组件就会展现同样的,可以使用这个来优化组件的性能。仅用于拥有简单和的组件。虽然提供简单的来提升性能,但是如果有更特殊的需求时怎么办如果组件有复杂的和怎么办这个时候就可使用来进行更加定制化的性能优化。 React: 一个用于构建用户界面的JAVASCRIPT库. React仅仅专注于UI层;它使用虚拟DOM技术,以保证它UI的高速渲染;它使用单向数据...

    oysun 评论0 收藏0
  • react基本原理及性能优化

    摘要:对同一层级的子节点进行处理时,会根据进行简要的复用。或者直接使用,原理一致。 一、从React原理谈起 react是什么? showImg(https://segmentfault.com/img/bVbcYvf?w=1140&h=384); react是用于构建用户界面的JS框架。因此react只负责解决view层的渲染。 react做了什么? Virtual Dom模型 生命周期...

    pinecone 评论0 收藏0
  • 【译】React应用性能优化

    摘要:应用主要的的性能瓶颈来自于一些冗余的程序处理以及组件中的的过程。为了避免这种情况,在你的应用中尽可能多的让返回。使用工具将帮助你找到应用程序中特定的性能问题。这个工具跟用起来很像,但是它是专门用来检测应用性能的。 这段时间对自己写的React应用的性能做了一些分析以及优化,发现项目中产生性能问题的原因主要来自两个方面: 大量的数据渲染使组件进行不必要的diff过程,导致应用卡顿; 部...

    txgcwm 评论0 收藏0
  • React 是怎样炼成的

    摘要:唯一不足的是,这种开发方式容易造成注入等安全问题。其中,最棘手的是如何再现中的更新机制。换句话来说,节点是包含状态的。对于没有改变的节点,让它保持原样不动,仅仅创建并替换变更过的节点。是树形结构,所以算法必须是针对树形结构的。 本文主要讲述 React 的诞生过程和优化思路。 内容整理自 2014 年的 OSCON - React Architecture by vjeux,虽然从今天...

    lijinke666 评论0 收藏0
  • 从头实现一个简易版React(三)

    摘要:写在开头从头实现一个简易版二地址在上一节,我们的已经具备了渲染功能。参考资料,感谢几位前辈的分享陈屹深入技术栈 写在开头 从头实现一个简易版React(二)地址:https://segmentfault.com/a/11...在上一节,我们的react已经具备了渲染功能。在这一节我们将着重实现它的更新,说到更新,大家可能都会想到React的diff算法,它可以说是React性能高效的保...

    yvonne 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<