React Native 优化


Li Zheng flyskywhy@gmail.com

不建议使用 hooks

React. Too many hooks spoil the soup — why hooks are bad 说的缺点:

  • hooks 比 class 更容易写出糟糕的代码
  • React 的初始理念是单向数据流,但是 hooks 毁了它

为什么 React 现在要推行函数式组件,用 class 不好吗? 说的缺点:

  • “useRef也是同理,ref会造成组件树之间相互影响,它是react团队开的后门”,说的其实是一旦使用 useRef ,就无法享受 concurrent 并发渲染模式的高性能了,而很多时候不得不用到 useRef ……
  • hooks 心智负担太重
  • 后端都是 OOP,转前端 OOP 很容易。但倘若前端陡然变成 FP,学习成本激增

至于整个 APP 使用 hooks 重写后可以得到后续 React 版本并发渲染模式的加持从而性能更高的优点?其实基于上面的缺点,那还不如使用 @flyskywhy/react-native-gcanvas 来进行无 render 绘画或是使用本文介绍的其它性能优化方法。

redux 性能优化

首先需要知道,即使 mapStateToProps() 中没什么内容,只要 redux 的 store 有改变,仍然会被执行。

如果使用 store 数据的组件代码的 mapStateToProps() 中使用如 ...state.userScreenUI 这样的写法,当 action 触发 userScreenUI 中 state 改变,则比如 react-navigation 的 router 栈中所有使用 ...state.userScreenUI 的写法来进行返回的 mapStateToProps() 所在组件的 render 方法将会被触发,无论该组件界面是否可见,也就是说引发了不必要的渲染。

因此请不要在 mapStateToProps() 中返回当前组件用不到的值。可以采用将 ...state.userScreenUI 手动展开成比如 pullRefreshPending: state.userScreenUI.pullRefreshPending 的写法,这样就算 action 触发了 state.userScreenUI 这个引用值的改变,但只要 state.userScreenUI.pullRefreshPending 这个比如 boolean 类型的非引用值没有改变,就不会重新 render 。当然如果是为了比如跟随浏览器(通过 react-native-web 运行)页面大小改变而改变所特别添加的类似 width: state.utils.width 这样的则不算没有用处的值,因为就算 render() 中没有用到 width ,我们也是希望 width 改变时重新 render 的,而 mapStateToProps() 返回 width 这个非引用值在改变时,就能重新 render 。

总之,只要 mapStateToProps() 返回的那些 props 中有引用值,且引用值会改变的,在没有使用下面提到的 shouldComponentUpdate()react-fast-compare 组件来不比较引用的地址(也就是引用值)而只比较具体内容的情况下,就会重新 render 。因此值得注意的是,还有一种隐含情况程序员可能会漏掉,也就是下面的写法

export function mapStateToProps(state, props) {
  const someArray = state.device.someArray || [];

  return {
    someArray, // 这种写法在 someArray 被赋值为上面的 [] 时就会触发重新 render
    // someArray: state.device.someArray, // 这种写法在 state.device.someArray 没有改变时不会重新 render
    height: state.utils.height,
    width: state.utils.width,
  };
}

会由于 [] 写法实际上是在内存中 new 了一个新数组对象并将该对象的引用值赋给了 someArray ,此时 mapStateToProps() 以之返回的话就会重新 render 。

一句话,只要 mapStateToProps() 返回的那些 props 中有引用值,最好就使用 shouldComponentUpdate()react-fast-compare 组件进行配合。

react-fast-compare 组件

之所以 react-fast-compare 组件很重要,是因为 redux 的 store 改变时,整个 store 的 state 的引用地址都改变了( redux 使用的是复制并修改的原理),因此只要不是 number 或 string 之类的直接值,而是 []{} 之类的引用值,都需要借助 react-fast-compare 组件来进行修改与否的判断。

之所以不使用比较流行的 immutable 组件而使用 react-fast-compare 组件,是因为发现 immutable.is() 方法无法正确比对数组(至少在 immutable@3.8.2 上发现有这个问题)

如果你的代码中用到了除 immutable.is() 之外的其它 immutable 数据结构,则可能需要让 react-fast-compare Working with Immutable.js structures

生命周期函数性能优化

react.Component 组件中添加如下生命周期函数代码即可基本避免不必要的重新渲染:
import isEqual from ‘react-fast-compare’;

  shouldComponentUpdate(nextProps, nextState = {}) {
    return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
  }

另外,即使在 shouldComponentUpdate() 中使用 react-fast-compare 组件判断从而避免了重新 render ,但是避免不了生命周期函数 getDerivedStateFromProps() 的执行,因此如果使用了 getDerivedStateFromProps() ,就可能需要在 getDerivedStateFromProps() 也应用 react-fast-compare 组件判断。

Text 控件

Android 默认背景是透明的, iOS 默认有个白色的背景,造成很多 UI 在 iOS 上显示不正常,如果不使用 Text 的背景时,可将背景设置为透明

backgroundColor: 'transparent'

其它

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值