2020 年谈 React Native,在日新月异的前端圈,可能算比较另类了。文章动笔之前我也犹豫过,但是想到写技术文章又不是赶时髦,啥新潮写啥,所以还是动笔写了这篇 React Native 性能优化的文章。
本文谈到的 React Native 性能优化,还没到修改 React Native 源码那种地步,所以通用性很强,对大部分 RN 开发者来说都用得着。
本文的内容,一部分是 React/RN/Android/iOS 官方推荐的优化建议,一部分是啃源码发现的优化点,还有一部分是可以解决一些性能瓶颈的优秀的开源框架。本文总结的内容你很少在网络上看到,所以看完后一定会有所收获。如果觉得写的不错,请不要吝啬你的赞,把这篇 1w 多字的文章分享出去,让更多的人看到。
看文章前要明确一点,一些优化建议并不是对所有团队都适用。有的团队把 React Native 当增强版网页使用,有的团队用 React Native 实现非核心功能,有的团队把 React Native 当核心架构,不同的定位需要不同的选型。对于这些场景,我在文中也会提一下,具体使用还需要各位开发者定夺。
目录:
一、减少 re-render
二、减轻渲染压力
三、图片优化那些事
四、对象创建调用分离
五、动画性能优化
六、长列表性能优化
七、React Native 性能优化用到的工具
一、减少 re-render
因为 React Native 也是 React 生态系统的一份子,所以很多 React 的优化技巧可以用到这里,所以文章刚开始先从大家最熟悉的地方开始。
对于 React 来说,减少 re-render 可以说是收益最高的事情了。
1️⃣ shouldComponentUpdate
文档:react.docschina.org/docs/optimi…
简单式例:
class Button extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
return false;
}
render() {
return <button color={this.props.color} />;
}
}
无论哪篇文章,谈到 React 性能优化,shouldComponentUpdate 一定是座上宾。
我们通过这个 API,可以拿到前后状态的 state/props,然后手动检查状态是否发生了变更,再根据变更情况来决定组件是否需要重新渲染。
官方文档对 shouldComponentUpdate 的作用原理和使用场景已经说的非常清晰了,我就没有必要搬运文章了。在实际项目中,阅文集团的 React Native 应用「元气阅读」也做了很好的示范, Twitter 的性能优化分享也做的图文并茂,可有很高的参考价值,对此感兴趣的同学可以点击跳转查看。
在此我想提醒的是,shouldComponentUpdate 是强业务逻辑相关的。 如果使用这个 API,你必须考虑和此组件相关的所有 props 和 state,如果有遗漏,就有可能出现数据和视图不统一的情况。所以使用的时候一定非常小心。
2️⃣ React.memo
文档:react.docschina.org/docs/react-…
React.memo 是 React v16.6 中引入的新功能,是一个专门针对 React 函数组件的高阶组件。
默认情况下,它和 PureComponent 一样,都是进行浅比较,因为就是个高阶组件,在原有的组件上套一层就可以了:
const MemoButton = React.memo(function Button(props) {
return <button color={this.props.color} />;
});
如果想和 shouldComponentUpdate 一样,自定义比较过程,React.memo 还支持传入自定义比较函数:
function Button(props) {
return <button color={this.props.color} />;
}
function areEqual(prevProps, nextProps) {
if (prevProps.color !== nextProps.color) {
return false;
}
return true;
}
export default React.memo(MyComponent, areEqual);
值得注意的是,areEqual() 这个函数的返回值和 shouldComponentUpdate 正好相反,如果 props 相等,areEqual()返回的是 true,shouldComponentUpdate 却返回的是 false。
3️⃣ React.PureComponent
文档:react.docschina.org/docs/react-…
简单式例:
class PureComponentButton extends React.PureComponent {
render() {
return <button color={this.props.color} />;
}
}
和 shouldComponentUpdate 相对应,React 还有一个类似的组件 React.PureComponent,在组件更新前对 props 和 state 做一次浅比较。所以涉及数据嵌套层级过多时,比如说你 props 传入了一个两层嵌套的 Object,这时候 shouldComponentUpdate 就很为难了:我到底是更新呢还是不更新呢?
考虑到上面的情况,我在项目中一般很少用 PureComponent。虽然很简单易用,但是面对复杂逻辑时,反而不如利用 shouldComponentUpdate 手动管理简单粗暴。当然这个只是个人的开发习惯,社区上也有其他的解决方案:
把组件细分为很小的子组件,然后统一用 PureComponent 进行渲染时机的管理使用 immutable 对象,再配合 PureComponent 进行数据比较( 参考链接:有赞 React 优化)......
在这个问题上仁者见仁智者见智,在不影响功能的前提下,主要是看团队选型,只要提前约定好,其实在日常开发中工作量都是差不多的(毕竟不是每个页面都有必要进行性能优化)。
二、减轻渲染压力
React Native 的布局系统底层依赖的是 Yoga 这个跨平台布局库,将虚拟 DOM 映射到原生布局节点的。在 Web 开发中,99% 的情况下都是一个 Virtual DOM 对应一个真实 DOM 的,那么在 React Native 中也是一一对应的关系吗?我们写个简单的例子来探索一下。
我们先用 JSX 写两个橙色底的卡片,除了卡片文字,第一个卡片还嵌套一个黄色 View,第二个卡片嵌套一个空 View:
// 以下示例 code 只保留了核心结构和样式,领会精神即可
render() {
return (
<View>
<View style={
{backgroundColor: 'orange'}}>
<View style={
{backgroundColor: 'yellow'}}>
<Text>Card2</Text>
</View>
</View>
<View style={
{backgroundColor: 'orange'}}>
<View>
<Text>Card2</Text>
</View>
</View>
</View>
);
};
用 react-devtools 查看 React 嵌套层级时如下所示:
![](https://img-blog.csdnimg.cn/img_convert/6da311a9ae1d49730ef97967b93e5082.webp?x-oss-process=image/format,png)
从上图中可以看出,React 组件和代码写的结构还是一一对应的。<