【翻译】光速React – Vixlet

翻译原文链接:https://blog.vixlet.com/react-at-light-speed-78cd172a6411

个人翻译小站链接:http://www.zcfy.cc/article/react-at-light-speed-vixlet-2920.html

在过去的几年里, 我们Vixlet (http://www.vixlet.com) 的web团队,着手了一项激动人心的项目,将我们的整个web应用迁往React+Redux的建设。对于我们整个团队来说

这是一个不断增长的机会,而且在这个项目过程中,我们一直充满着挑战。

自此我们的web-app中,包含有几百甚至上千的媒体,文本,视频以及链接等内容,我们花了很长的时间去摸索关于react构建的方式,这里我们将分享一些踩过的经验。

声明: 讲解的这些经验和方法,已经能够很好的满足我们特殊应用的需求,然而,如果是整体开发的话,将你的应用和团队考虑其中至关重要,React的速度是相当快的,所以你可能没有必要很精确的了解到我们的使用场景,但是,我们希望你能发现一些发送的有益的信息。

基本原理

向更大的世界迈出一步.

The render() 函数

作为一个通用原则,尽量在render函数里面少做事,如果实在很有必要运行一些复杂的操作和计算,也许可以考虑将他们移到 memoized 函数里面, 这样得到的结果能够被缓存.了解 Lodash.memoize 关于 memoization函数的模型.

相反地,去避免更改巨大的,轻易计算的值在组件中的状态是很重要的。例如,如果props参数同时包含 firstName 和 lastName,那么就没必要在state状态里面包含 fullName ,因为它很容易从props属性里面获得。 如果一个值能以一种很有效的方式通过props获得,通过使用通用的字符串连接,或者基本的的算法操作,那么我们就没必要更改状态来获取该值了。

Prop 和 Reconciliation

这是很重要的,记住React触发时,是会重新渲染的,其prop值(或者state状态)跟之前的值是不相等的。它包含了在嵌套组件,且其props和state包含对象或者数组之内的任何变化,记住这一点,这是很重要的情况,就是可能不经意的render循环,去创造prop或者state的值,就可能引起巨大的性能冲击。

例如: 函数绑定问题

例如: 对象或者数组的字面值

例如_: 注意fallback返回的值

尽可能的保证Props(和state)最小

一般来讲,props是在被需要的情况下,才会传递给一个组件,通过一个大且复杂的对象,或者很多个单独的props传递给组件,仅仅只是为了给其子组件传递值,但这会引起不必要的组件渲染(同时增加了开发的复杂性).

在我们Vixlet这边,我们使用Redux作为state的容器,因此在我们的这种情况,大部分是从react-redux中使用connect()函数,根据组件中的每一个等级去直接获取需要的数据。connect()函数是非常高性能并且占用的开销非常小。

组件方法

自从给每一个组件实列赋予了组件的方法,如果可以的,你要么使用纯粹的来自helper/util模板中的函数,要么使用静态类方法,这里有一个特别值得注意的地方,就是当有很大数字的组件在app里面进行渲染的时候。

高级

读完我的观点,jank变得邪恶了!

shouldComponentUpdate()

React生命周期中包含一个的方法 [shouldComponentUpdate()](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate).这个方法可以告诉React,组件是否应该被渲染或者不依赖当前或者下一个props/state的值。

然而使用这个方法有个问题,那就是开发者必须仔细考虑每一种重新渲染发生的条件。这就使逻辑变得很复杂,通常来说,这太痛苦了,如果你真的需要它,那你就使用 shouldComponentUpdate()方法,但是对于很多的情况,一般都有更好的选择。

React.PureComponent

React v15版本开始,其包含了 PureComponent类,可以用来建立组件。React.PureComponent基本实现了它自己的shouldComponentUpdate()方法,并且能够自动判断出当前以及下一个props/state组件之间的比较。如果想看更多的信息,请至Stack Overflow:

http://stackoverflow.com/questions/36084515/how-does-shallow-compare-work-in-react

在几乎所有的情况中,React.PureComponent无疑是比React.Component更好的选择.当创建一个新的组件时候,试着将其建立为一个纯粹的组件先,并且将组件功能引入,使用React.Component.

更多信息: [React.PureComponent](https://facebook.github.io/react/docs/react-api.html#react.purecomponent)官方React文档

组件运行分析 (in Chrome)

在最新Chrome版本,新增了一个建立时间表功能的工具,它可以将React组件渲染详细的信息,以及所花的时间显示出来。使用该功能只需要添加?react_perf放在你想测试的url的后面即可。React渲染的时间列表数据,将会在用户时间部分之下显示。

更多信息: Profiling Components with Chrome Timeline官方React文档

有用的Utility: why-did-you-update

这是一个很好的NPM包,当没有必要重新渲染组件的时候,它能进行补丁,在console里面打印出来通知。

注: 这个模块能够使用过滤器进行初始化,去匹配特殊的你想要的组件,否则你的所有console出来的东西,都会被识别为垃圾信息,或者你的浏览器可能会崩溃,至 why-did-you-update docs获取更多细节信息。

常见的性能陷阱

setTimeout() and setInterval()

使用 setTimeout() or setInterval()在一个 React组件之中,需要极其的小心。这里几乎是更好的选择去使用 ‘resize’ 和 ‘scroll’ 事件 (注: 见下一章节需要注意的事项).

如果你需要使用 setTimeout() or setInterval(), 你必须 遵循下面几个禁令

极其短时间内持续发生不要使用

短时间内持续发生是没有必要使用的,特别是小于100ms的,如果更短的时间内,真的需要,也许你可以使用 [window.requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) 来代替.

参考这些取消/清除函数

setTimeout() and setInterval()都返回一个唯一的标识符,对于延迟函数,如果有必要可以对其进行取消操作。自从这些函数在全局范围内运行,他们不需要关心你的组件是否已经不在,它会直接导致报错或者停止运行。+

注: 这是真的对于window.requestAnimationFrame()来说

最简单的解决这个问题的方案其实是使用 react-timeoutNPM包,它可以提供高阶组件,确保它能够自动使用上面提到的那个东西,它添加了包裹在组件的props中的setTimeout/setInterval等函数(特别感谢Vixlet开发者Carl Pillot 可戳这里进入)

如果你不希望引入一个依赖,并且想要用你自己的方案去解决这个问题,下面这些可能对你的会有帮助:

如果你在使用requestAnimationFrame()来控制动画循环,你可以使用很小的通知来进行类似的处理。

去抖和防流事件

一定程度上来说,正常的事件是极其迅速的,像”scroll”,”resize”.这是很明智的,去抖事件,特别是如果这些事件被解决的话,远远比那些极其基本的功能执行的好。

Lodash有[_.debounce](https://lodash.com/docs/#debounce) 方法. 这里依然是一个独立的[debounce](https://www.npmjs.com/package/debounce)NPM包

“但是我真的需要scroll/resize/无论什么事件立即响应”

我曾经发现了一种模式可以以一种高性能的方式来解决这类事件响应问题,那就是使用 requestAnimationFrame()来监听事件开始和结束的时间,然后, [debounce()](https://lodash.com/docs#debounce)函数通过使用 trailing选项来设置为 true(这就意味着函数仅仅在节流函数结束之后才结束)来阻止监听这个值,看下面的例子

密集的CPU任务导致线程阻塞

毫无疑问,很多任务一起将会加强CPU的损耗,因此引起主要的渲染阻塞,一些例子包括非常复杂的数学计算,通过一个很大的数组进行迭代,通过使用File api来进行渲染/覆写. 加密或者解密图像数据从`` object中.

如果在所有的情节当中,也许使用web搬运工,将其一些功能性的东西搬移到另外一个线程中会更好,因此,我们的主要渲染进程中能够顺利的进行。

阅读这些

MDN 文章: Using Web Workers

MDN 文档: Worker API

结尾

我们希望你已经发现上面这些有用的建议和信息。最后说一句,如果没有我们的Vixlet团队,上面这些技巧和提示方法是不可能被搜索出来,并且很好的运行的,他们真的是我工作以来,有幸接触到的一群非常优秀的团队伙伴。

在React之外进行升华,持续学习和练习,希望和你一起进步!

谢谢 Matt Lubner

时间: 2024-10-24 12:08:49

【翻译】光速React – Vixlet的相关文章

React Native 初识

Facebook 在 React.js Conf 2015 大会上推出了基于 JavaScript 的开源框架 React Native,本中文教程翻译自 React Native 官方文档. React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用.在 JavaScript 中用 React 抽象操作系统原生的 UI 组件,代替 DOM 元素来渲染等. React Native 使你能够使用基于 J

Thinking in React

本文翻译自React的官方博客,详情请阅读原文. React非常适合构建组件化的应用,它注重高性能,因此组建的重用,项目的扩展都十分灵活,Facebook和instagram的不少商业项目使用了此框架. 本文主要通过“输入查询数据”这个简单的demo来说明或者学习如何用React来架构. 数据模型 我们需要根据JSON API来显示并且操作数据,最终的可视化操作是基于JSON数据的基础之上.最终的效果图如下: 以下便是我们模拟的JSON数据: [ {category: "Sporting Goo

从零开始的Android新项目10 - React Native & Redux

本篇来讲讲 React Native 和 Redux,和其他一上来就啪啪啪丢上来一堆翻译的东西不同,本文会从简单的例子入手,让大家能快速地明白 React Native 是什么,Redux 和常见的 MVC.MVP 等有什么区别,怎么去组织一个 Redux 架构的 React Native 项目. 为避免大家还没入门就放弃,预计下一篇才会从我们项目中的实践出发,讲讲更复杂的应用场景. 什么是React Native React Native 使你能够基于 JavaScript 和 React 在

Learning React Native笔记

React Native作为一个新事物,相关的资料还不多 官方的文档比较简单,缺少一些系统的例子 在对React Native的应用中,迫切的想学习一些别人的最佳实践.所以想通过看书系统的学习下 之前看过奇舞团翻译的React Native:用JavaScript开发移动应用,书的内容质量不太高 最近花了三天读完Learning React Native,觉得内容质量还是要好过前一本书不少的 <Learning React Native>这本书在我看来,定位也是一本入门书.目标是了解React

掘金翻译计划

原文:https://github.com/Ruixi/gold-miner 掘金翻译计划是一个翻译优质互联网技术文章的社区,文章来源为掘金上的英文分享文章.内容覆盖 Android.iOS.前端.后端.产品.设计等领域,读者为热爱新技术的新锐开 发者. 掘金翻译计划目前翻译完成 84 余篇文章,共有 108 名译者贡献翻译. 如何参与翻译 在 待认领文章列表 中认领翻译文章(如果是第一次认领,介绍一下自己就更好咯) 认领通过后,Fork 此仓库开始翻译 翻译完成,发送 Pull Request

Facebook React Native 中文教程一:介绍

React Native 中文版 Facebook 在 [React.js Conf 2015](http://conf.reactjs.com/) 大会上推出了基于 JavaScript 的开源框架 [React Native](http://facebook.github.io/react-native/),本中文教程翻译自 [React Native 官方文档](http://facebook.github.io/react-native/docs/getting-started.html

React躬行记(16)——React源码分析

React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版本很接近. 一.目录结构 React采用了由Lerna维护monorepo方式进行代码管理,即用一个仓库管理多个模块(module)或包(package).在React仓库的根目录中,包含三个目录: (1)fixtures,给源码贡献者准备的测试用例. (2)packages,React库提供的包的

一套代码小程序&amp;Web&amp;Native运行的探索01

前言 前面我们对微信小程序进行了研究:[微信小程序项目实践总结]30分钟从陌生到熟悉 并且用小程序翻写了之前一个demo:[组件化开发]前端进阶篇之如何编写可维护可升级的代码 之前一直在跟业务方打交道后面研究了下后端,期间还做了一些运营.管理相关工作,哈哈,最近一年工作经历十分丰富啊,生命在于不断的尝试嘛. 当然,不可避免的在前端技术一块也稍微有点落后,对React&Vue没有进行过深入一点的研究,这里得空我们便来一起研究一番(回想起来写代码的日子才是最快乐的??),因为我们现在也慢慢在切Rea

Thinking in React(翻译)

下面是React官方文档中的Thinking inReact文章的翻译,第一次翻译英文的文章,肯定有非常多不对的地方,还望多多包涵. 原文地址:https://facebook.github.io/react/docs/thinking-in-react.html 原文開始 ---------------------------------------------我是分隔符------------------------------------------ Thinking in React b