React性能优化必知必会

tips:欢迎关注我在github的博客点击查看

使用React.pureComponent,React.memo做性能优化

讲这两个api前需要提及React组件的更新,看这图:

image

如果shouldComponentUpdate 返回false,那就一定不用rerender(重新渲染 )更新这个组件了,不用执行调用render函数,返回React elements去做比对(vdoms diff),而且这个组件的子组件也不用去调用shouldComponentUpdate判断是否要更新了,因为父组件没更新(自己也没改变state)。但是如果shouldComponentUpdate 返回true,会进行组件的React elements比对,如果相同,则不用真实rerender这个组件,否则会rerender。

React.pureComponent

React.PureComponent,字面意思就是纯组件,可类比存函数概念,所以当有一致的渲染输入(props和state)时,因为有同样的渲染效果,所以就不rerender了,以此优化性能。

React.Component是react的普通类组件,有个生命周期:在重新渲染之前应调用shouldComponentUpdate。在初始渲染之后,当接收到新的props或state时,在重新渲染之前应调用shouldComponentUpdate()。默认为true。

而React.PureComponent与React.Component之间的区别在于,React.Component虽然可以在shouldComponentUpdate()这个生命周期中进行自定义比较决定是否rerender,这样可以做性能优化。但是React.PureComponent的shouldComponentUpdate默认内置去浅比较prop和state来决定要不要rerender组件,解决了大量在Component虽然可以在shouldComponentUpdate写差不多模板代码的问题。

React.memo

React.pureComponent 服务于class组件,React.memo服务于函数组件,两者服务对象不同,功能相同。有点不同的是,React.memo只会浅比较props,以前函数式组件是stateless的,所以浅比较props也就够了,现依旧如此,useState hook带来的state改变和useContext hook带来的context改变,React.memo包(这货是个高阶组件)的组件仍会rerender。而且React.memo可以传第二个参数来实现类似shouldComponentUpdate的功能自定义决定组件是否rerender => React.memo(MyComponent, areEqual);。当然,return 值的意义两者反着来。

结论

也就是React.PureComponent与React.memo默认帮你用浅比较去决定要不要rerender,做性能优化。

当然,这边要注意不要mutable地去改动两者的props或者PureComponent的state,这样浅比较的结果为false,也就是这样你就算改了也不会rerender, 除非调用forceUpdate()强制更新。

可是,这样很多同学就会有事没事就React.PureComponent,React.memo一把梭,好像吃不用钱的蜜糖。但是,甲之蜜糖 乙之砒霜,并不是所有场合都适合使用这两个东东,用pureComponent会进行浅比较state和props,这个比较也是需要开销的,所以当你知道组件一定需要重新渲染时,就不要用pureComponent或者shouldComponentUpdate去做浅比较了,shouldComponentUpdate默认值为true,省了这个浅比较,直接去比较React元素有没有变,没有变就不更新,有变才更新。

以下内容来自React开发团队

If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want to rerender, all of the time spent checking whether you should have rerendered is wasted.

image

旦总还专门发推 (不是朱一旦,手动狗头)

使用react hook: useCallback, useMemo做性能优化

这两个因为作用有点类似,都是用记忆计算结果来避免render的时候重新做一些计算,节省开销。不同的是,useMemo是记忆值,也就是返回值:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

而useCallback是记忆函数,也就是返回一个函数,

const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b],);

useCallback(fn, deps) 等同于 useMemo(() => fn, deps).

而且我原以为会缓存之前多次计算过的东西,没想到测试了下,只会缓存记忆上一次的,所以只有上一次和本次的依赖值相同时,才会读取上一次的计算结果,但是上一次之前的就算有跟本次的依赖值相同的,依旧要重新计算。如下图

image.png

useCallback 可以确保在重新渲染之间那个回调不会发生变化,除非依赖(第二个参数)改变

举个例子

image

图中RenderCallLogCallControl组件里面有一个onTransfer方法,如果不写useCallback,那么每次RenderCallLogCallControl组件rerender,也就是这个函数组件会被重新执行一次,因而onTransfer会跟着被重新创建,就算onTransfer还是一样的函数内容,但实际上引用地址不一样,那么EvSmallCallControl和其子组件TransferCallButton接收到onTransfer的onTransfer prop即有变动,该组件因此也会rerender。

这种情况并不想因为onTransfer被重复创建而rerender组件,性能浪费,那么可以用useCallback把这个onTransfer函数memo起来,让其不会变动(除非依赖transferRef改变), prop有onTransfer的组件也不会因此多做没必要的rerender。

reference

Deep dive with the React DevTools profiler
Introducing the React Profiler
Optimizing Performance
React Top-Level API
should-i-use-react-purecomponent-everywhere

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342