资讯专栏INFORMATION COLUMN

React怎么判断什么时候该重新渲染组件?

Alan / 1717人阅读

摘要:我们需要关注的一方面是如何决定什么时候重新渲染组件。组件获得新的状态然后决定是否应该重新渲染组件。比起让每次都重新渲染,你可以告诉你什么时候不像触发重新渲染。重要提示当子组件的的变化时返回并不能阻止它们重渲染。

React因为他的性能而著名。因为他有一个虚拟DOM层并且只有在需要时才更新真实DOM。即使是同样地信息这也比一直直接更新DOM要快很多。但是,React的智能仅此而已(目前为止),我们的任务是知道React的预期行为以及限制,这样我们才不会意外损失性能。

我们需要关注的一方面是React如何决定什么时候重新渲染组件。不是重新渲染DOM节点,只是调用render方法来改变虚拟DOM。我们可以通过告诉React什么时候需要渲染什么时候不需要渲染来帮助React。让我们依次来看看这些。

1. 组件的状态发生改变

只有在组件的state变化时才会出发组件的重新渲染。状态的改变可以因为props的改变,或者直接通过setState方法改变。组件获得新的状态然后React决定是否应该重新渲染组件。不幸的是,React难以置信简单地将默认行为设计为每次都重新渲染。

组件改变?重新渲染。父组件改变?重新渲染。一部分没有导致视图改变的props改变?重新渲染。

class Todo extends React.Component {

    componentDidMount() {
        setInterval(() => {
            this.setState(() => {
                console.log("setting state");
                return { unseen: "does not display" }
            });
        }, 1000);
    }

    render() {
        console.log("render called");
        return (
...
); } }

在这个(非常刻意的)例子中,Todo将会每秒重新渲染依次,即使render方法根本没有使用unseen。事实上,unseen值甚至都不改变。你可以在CodePen里查看这个例子的实际版本。

好吧,但是每次都重新渲染没有什么帮助。

我的意思是,我非常感谢React的细心谨慎。如果状态改变但是组件没有正确渲染的话更糟。权衡之下,每次都重新渲染绝对是一个安全的选择。

但是重新渲染的时间成本看起来非常昂贵(例子里非常夸张地表现了出来)。

是的,在不必要的时候重新渲染会浪费循环并且不是一个好的想好。但是,React不能知道什么时候可以安全的跳过重新渲染,所以React无论是否重要每次都重新渲染。

我们如何告诉React跳过重新渲染?

那就是第二点要说的内容。

2. shouldComponentUpdate方法

shouldComponentUpdate方法默认返回true,这就是导致每次更新都重新渲染的原因。但是你可以在需要优化性能时重写这个方法来让React更智能。比起让React每次都重新渲染,你可以告诉React你什么时候不像触发重新渲染。

当React将要渲染组件时他会执行shouldComponentUpdate方法来看它是否返回true(组件应该更新,也就是重新渲染)。所以你需要重写shouldComponentUpdate方法让它根据情况返回true或者false来告诉React什么时候重新渲染什么时候跳过重新渲染。

当你使用shouldComponentUpdate方法你需要考虑哪些数据对与重新渲染重要。让我们回到这个例子。

正如你所看到的,我们只想在titledone属性改变的时候重新渲染Todo。我们不关心unseen是否改变,所以我没有把它包含在shouldComponentUpdate方法中。

当React渲染Todo组件(通过setState触发)他会首先检查状态是否改变(通过propsstate)。假设状态改变了(因为我们显式地调用了setState所以这会发生)React会检查TodoshouldComponentUpdate方法。React会根据shouldComponentUpdate方法返回值为true或者false来决定从哪里渲染。

更新后的代码仍然会每秒调用一次setState但是render只有在第一次加载时(或者titledone属性改变后)才会调用。你可以在这里看到。

看起来有很多工作去做。

是的,这个例子非常冗长因为有两个属性(titledone)需要关注并且只有一个可以忽略(unseen)。根据你的数据可能仅检查一个或两个属性并且忽略其他会更有意义。

重要提示

当子组件的的state变化时, 返回false并不能阻止它们重渲染。

– Facebook的React文档

这作用于子组件的状态而不是他们的props。所以如果一个子组件内部管理了一些他自己的状态(使用他自己的setState),这仍然会更新。但是如果父组件的shouldComponentUpdate方法返回了false就不会传递更新后的props给他的子组件,所以子组件不会重渲染,即使他们的props变化了。

额外内容:简单性能测试

编写并且在shouldComponentUpdate方法中运行计算的时间成本可能会很昂贵,所以你需要确保值得做。在写shouldComponentUpdate方法前你可以测试React一个周期默认会消耗多少时间。有了这个信息做参考,在做性能优化时你可以做一个不盲目的决定。

使用React的性能工具去发现浪费的周期:

Perf.start()
// Do the render
Perf.stop()
Perf.printWasted()

哪一个组件浪费了很多渲染周期?你怎么通过shouldComponentUpdate方法让他们更智能?试着使用性能测试工具来比较他们的性能。

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

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

相关文章

  • 30分钟精通React今年最劲爆的新特性——React Hooks

    摘要:所以我们做的事情其实就是,声明了一个状态变量,把它的初始值设为,同时提供了一个可以更改的函数。 你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? ——拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function。 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? ——拥有了Hooks,生命周期钩子函数可以先丢一边了。 你在还...

    icattlecoder 评论0 收藏0
  • React 328道最全面试题(持续更新)

    摘要:希望大家在这浮夸的前端圈里,保持冷静,坚持每天花分钟来学习与思考。 今天的React题没有太多的故事…… 半个月前出了248个Vue的知识点,受到很多朋友的关注,都强烈要求再出多些React相前的面试题,受到大家的邀请,我又找了20多个React的使用者,他们给出了328道React的面试题,由我整理好发给大家,同时发布在了前端面试每日3+1的React专题,希望对大家有所帮助,同时大...

    kumfo 评论0 收藏0
  • React setState源码实现理解

    摘要:新的值回调函数。官方注解是给组件做个标记需要重新渲染,并且将可选的回调函数添加到函数列表中,这些函数将在重新渲染的时候执行。一共做了两件事一是通过执行方法来更新组件二是若方法传入了回调函数则将回调函数存入队列。 Q1 setState改变状态之后,不会立即更新state值。所以,如果改变state值,react是什么时候进行组件的更新呢?setState()到底做了一些什么呢? A1 ...

    xietao3 评论0 收藏0
  • react-lazy-load粗读

    摘要:粗读近来没什么特别要做的事,下班回来的空闲时间也比较多,所以抽空看看懒加载是怎么实现的,特别是看了下的库的实现。之先别关注,按他给注释说测试用。之是组件绑定事件时会触发的函数。 react-lazy-load粗读 近来没什么特别要做的事,下班回来的空闲时间也比较多,所以抽空看看懒加载是怎么实现的,特别是看了下 react-lazy-load 的库的实现。 懒加载 这里懒加载场景不是路由...

    dailybird 评论0 收藏0
  • 从Preact了解一个类React的框架是怎么实现的(二): 元素diff

    摘要:本系列文章将重点分析类似于的这类框架是如何实现的,欢迎大家关注和讨论。作为一个极度精简的库,函数是属于本身的。 前言   首先欢迎大家关注我的掘金账号和Github博客,也算是对我的一点鼓励,毕竟写东西没法获得变现,能坚持下去也是靠的是自己的热情和大家的鼓励。  之前分享过几篇关于React的文章: React技术内幕: key带来了什么 React技术内幕: setState的秘密...

    张巨伟 评论0 收藏0

发表评论

0条评论

Alan

|高级讲师

TA的文章

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