React Native性能优化

使用Pure Component

在React项目中,渲染复杂(也可以是所有组件)的组件最好继承于PureComponent,这样通过shouldComponentUpdate可以避免不必要的render调用和虚拟DOM的比较。

// ES6 写法
import React, { PureComponent } from 'react'

export default class Banner extends PureComponent {
    // ...
}

// React.createClass写法
import React from 'react'
import PureRenderMixin from 'react-addons-pure-render-mixin'

const Banner = React.createClass({
    mixins: [ PureComponent ],

    // ..
})

合理使用箭头函数(尽量避免)

在定义组件时,我们经常会用到箭头函数,比如在ES6 class中为了保持住this的引用,定义ref

import React, { PureComponent } from 'react'

export default class Banner extends PureComponent {
    render() {
        return (
            <FlatList
                ref={ v => this._scrollRef = v }
                onScroll={evt => this._onScroll(evt)}
                data={this.props.listData}
                renderItem={(...args) => this._renderItem(...args)}
                extraData={{
                    id: this.props.id,
                }}
            />
        )
    }
}
以上写法有一个问题,这样写每次调用Banner的render方法,ref, onScroll, renderItem, extraData都会重新创建,这样会使FlatList的PureComponent优化失效,从而导致不必要的render调用和虚拟DOM比较。
比较好的写法应当如下

import React, { PureComponent } from 'react'

export default class Banner extends PureComponent {
    _setScrollRef = (v) => {
        this._scrollRef = v;
    }

    _extraData = {}

    _getExtraData = () => {
        if (!this._extraData || this._extraData.id !== this.props.id) {
            this._extraData = {
                ...this._extraData,
                id: this.props.id,
            }
        }
        return this._extraData;
    }

    render() {
        return (
            <FlatList
                ref={ this._setScrollRef }
                onScroll={ this._onScroll }
                data={this.props.listData}
                renderItem={ this._renderItem }
                extraData={this._getExtraData()}
            />
        )
    }

    _renderItem = (v) => {
        // ...
    }

    _onScroll = (v) => {
        // ...
    }
}
如上面这种写法,如果id或listData不变,则FlatList将不会被无效调用render。
当然,并不是说你不能在项目中使用箭头函数,但当你的项目存在性能问题时,你应当考虑移除一些箭头函数。


组件接受最小单位的数据

在我们的业务项目中,通常都会用Redux管理数据,然后通过connect来将store中数据注入组件,也就是所谓的容器组件。
在定义容器组件的时候,一定要注意的是,只关注这个容器组件及其自组件所关心的数据,不要订阅无关数据。

// 方式一
connect((state) => {
    return state.homeData;
}, HomeActions)(ViewPager);

// 方式二
connect((state) => {
    return state.homeData.viewPagerData;
}, HomeActions)(ViewPager);

/**
* homeData数据结构
* {
*   navList: [],
*   cid: 0,
*   viewPagerData: [],
*   adUrl: null,
* }
*/
其实ViewPager所关注的只有viewPgaerData,如果如上面方式一订阅homeData下的所有数据,那当homeData中的其他字段变化,都会出发ViewPager render函数的调用和虚拟DOM比较。而方式二只订阅了ViewPager所关注的数据,这样其他字段的变化就不会出发到ViewPager的无效渲染。


使用Immutable数据

在使用Redux和PureComponent时,最好结合Immutable Data一起使用,这可以使props比较的更高效和准确。
一般比较好的做法是在Redux Store中将数据Immutable化和扁平化,在使用connect包装容器组件时,可以直接让其接收Immutable的数据。


使用FlatList/SectionList

当我们页面上需要展示一个很长的列表并且列表每一项图片还很多时,请使用FlatList或SectionList。
如果使用的还是ScrollView,对于长列表,RN会将所有项一次性全部渲染出来,这会出现两个问题,首先首次渲染用时会很长,即时在视窗范围外的节点也会全部被渲染,其次如果图片多了,会导致系统OOM。
ListView比ScrollView稍好,它带有分页功能,但它是增量渲染,也就是前面渲染的列表项不会在被销毁,会一直留在页面上,当滑动到底部,它和ScrollView展示的节点数就一致了,所以使用ListView并不能避免OOM。
FlatList和SectionList都是基于VirtualizedList使用的,在使用这两个组件时,默认会渲染当前屏幕的数据,然后上面10屏高度的数据,下面10屏高度的数据,这个设置可以通过windowSize来修改,所以在使用这两个列表组件时,就不存在增量的问题,不会出现OOM。


ScrollTabView的使用

ScrollTabView是用来做多Tab页切换的,当经常每个tab下都是一个长列表,如果一个一个切换到最后一个tab而不做任何优化的,而每个Tab下图片又很多的话,很大概率会出现OOM。
可以通过下面方式避免:

export default class ViewPager extends PureComponent {
    render() {
        return (
            <ScrollTabView
                ref="tabView"
                scrollWithoutAnimation={false}
                rerendingSiblingNumber={1}
            >
                {this.props.naviList.map((nav, i) => {
                    return (
                        <TabPage
                            tabLabel={nav.name}
                            onTabSwitch={this._onTabSwitch}
                            key={`tabpage-${nav.id}`}
                        />
                    );
                })}
            </ScrollTabView>
        )
    }
}

class TabPage extends PureComponent {
    render() {
        const tabSelected = this.props.currentTabIndex === this.props.tabIndex;
        return (
            <View style={{flex: 1, overflow: 'hidden', borderWidth: 0}}>
                <Image hidden={!tabSelected} source={{uri: 'https://xxx.png'}} />
            </View>
        );
    }
}

在每一个TabPage组件中,ScrollTabView会自动注入两个props,currentTabIndex表示当前显示的tab页的索引,tabIndex表示tab页自己的索引,当两者不一致,代表这个tab页不在视窗范围内,可以通过Image的hidde把正在显示的图片隐藏。


Android过渡绘制

在Android平台上,设置背景色当遵循设置最小化。因为大范围的设置背景色会导致过度绘制


内存优化


图片内存优化
在原生开发中,如果图片展示过多而得不到释放,会出现OOM的情况。所以在长列表或多Tab页面中,一定要想办法对图片进行回收,在RN里我们可以将不展现在视图范围内的图片用一个空白的View来代替,这样Native底层会对缓存的图片进行gc
View结构过多过于复杂优化
如果一个页面中创建的View过多,View嵌套过深,都会对性能产生不利影响。
对于View创建过多,可以从销毁不在视图范围内的View入手
对View嵌套过深的问题,可以想办法通过样式来精简
页面堆栈优化
在RN中,通过push方式切换页面,路由栈中原有页面并不会被销毁,而是通过translate方式移除到屏幕之外的地方,所以之前显示页面所占内存也并未被销毁,我们不应当无限制的往路由栈中压栈。
举个例子:在商品详情页下面有联想的相关商品,可以通过相关商品往路由栈无限的压商详页,原生处理方式是最多只保留当前商详页和最近两个的商详页,其他予以销毁。
参照原生处理,在RN中,我们也是可以做到这样处理的。可以通过Router中的reset(routes: Array<RouteType>, index)手动重置路由栈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Native 是一种基于 React 的跨平台移动应用开发框架,其性能受到多种因素的影响。以下是一些优化 React Native 应用性能的建议: 1. 减少渲染次数。React Native 的渲染是基于虚拟 DOM 的,因此组件的更新会引起重新渲染。减少组件的更新次数可以减少渲染次数。可以使用 shouldComponentUpdate 或 PureComponent 来避免不必要的渲染。 2. 使用 FlatList 或 SectionList。FlatList 和 SectionList 是 React Native 的内置组件,它们可以帮助减少渲染次数和内存使用。它们可以按需渲染列表项,而不是一次性渲染所有列表项。 3. 使用动画。React Native 提供了一些内置的动画组件和 API,可以让应用的界面更加流畅和生动。使用动画时,应尽量避免在渲染期间执行操作,以免影响性能。 4. 使用原生组件。React Native 允许开发者使用原生组件来替代一些 React Native 内置组件,以提高性能。例如,使用原生 ScrollView 替代 React Native 的 ScrollView。 5. 使用性能监测工具。React Native 提供了一些性能监测工具,例如 React Native Performance Monitor 和 Reactotron,可以帮助开发者分析应用的性能瓶颈,从而进行针对性的优化。 6. 使用代码分割。React Native 应用可以使用代码分割来减少应用的首次加载时间。可以使用 React Native 的内置代码分割工具或第三方工具进行代码分割。 7. 使用缓存。React Native 应用可以使用缓存技术来减少网络请求和数据处理的次数,从而提高应用的性能。可以使用内置的 AsyncStorage 或第三方缓存库来实现缓存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值