Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native性能优化:应该做和不应该做的 #24

Open
flytam opened this issue Mar 3, 2021 · 0 comments
Open

React Native性能优化:应该做和不应该做的 #24

flytam opened this issue Mar 3, 2021 · 0 comments
Labels
react New feature or request

Comments

@flytam
Copy link
Owner

flytam commented Mar 3, 2021

在使用一些框架例如React Native去实际开发移动端应用的时候,性能是一个重要的问题。React Native默认情况下的性能是没有问题的,但是在实际开发React Native的时候,我们也可能会遇到一些性能相关的问题。

这些问题是很难通过组件本身修复去解决的。在这篇文章中,我们会提供一些建议来优化开发React Native遇到的一些性能问题。

使用Image缓存解决方案

React Native在自带的组件库中提供了Image组件,可以用例展示图片。但是这个组件没有解决以下这些问题的开箱即用的解决方案:

  • 屏幕中渲染大量图片
  • 一般情况下性能比较低
  • 从缓存中加载性能比较低
  • 会有加载闪烁

React Native中的Image组件处理缓存图片的时候会像web 浏览器一样的行为,会可能导致上面提到的问题。可以通过使用第三方库react-native-fast-image来解决上面的这些问题。这个库在iOS和安卓上都可用并且能够有效的缓存图片

使用适当大小的图片

如果React Native APP依赖于使用大量的图像,那么优化图像对于APP的性能是很重要的。如果图片的尺寸没有得到合适的优化,渲染大量图片会导致在设备上占用大量的内存。这可能会导致APP崩溃

一些可以在React Native中有效优化图片的方案包括:

  • 使用PNG格式的图片而不是JPG
  • 使用尺寸更小的图片
  • 使用WEBP格式的图片。可以在iOS和Android平台减少29%的二进制大小。

避免不必要的渲染

React Native是基于React的库并且处理组件渲染的形式类似于React.js。因此在React中可用的优化方法也适用于React Native。一个优化方法就是避免不必要的渲染,在函数组件中可以通过使用React.memo()来完成。

React.memo是被用来进行处理记忆化(memoization)。记忆化的理念是:如果一个组件接收相同的props超过一次,它将会使用之前一次缓存的props。并且函数组件只会进行一次渲染返回jsx

例如下面Parent组件和Child组件的例子。Parent组件有一个count的state变量,每次button点击的时候更新count

当button点击的时候,即使Child组件的props属性text没有改变,每次Parent组件渲染都会造成Child组件的重新渲染。Child组件没有做任何和Parent组件有关的操作而仅仅是展示一些静态文本。这个行为可以通过把Child组件用React.memo()包着来进行优化

// Parent.js

const Parent = () => {
  const [count, setCount] = useState(0);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title='Press me' onPress={() => setCount(count + 1)} />
      <Child text='Placeholder text' />
    </View>
  );
};

// Child.js
const Child = React.Memo(({ text }) => {
  return <Text>{text}</Text>;
});

Animated库中使用nativeDriver

React Native中有很多方法可以写动画,最常用的方法就是使用Animated库

Animated

Animated会在动画执行之前,通过nativeDriver把动画发送到原生bridge中,这有助于动画独立于被阻塞的JavaScript线程执行,动画会执行比较流畅而不会丢帧

通过设置useNativeDriver的值为true,可以在Animated库中使用nativeDriver。下面的例子就是在ScrollView组件的onScroll事件中使用useNativeDriver

<ScrollView
  showsVerticalScrollIndicator={false}
  scrollEventThrottle={1}
  onScroll={Animated.event(
    [{ nativeEvent: { contentOffset: { y: animatedValue } } }],
    { useNativeDriver: true }
  )}
>
  // 组件的内容
</ScrollView>

使用Flipper进行调试

React Native 0.62.0版本介绍了一个新的调试工具Flipper。 这是一个给iOS、安卓和React Native使用的平台 。它直接集成在原生代码中,并且在React Native中开箱即用。

使用Flipper调试app不需要远程调试。需要一个本地连接的Metro实例来与React Native应用进行交互。它可通过React DevTools来检查组件树并检查React组件的state和属性。

它使用原生插件生态系统来调试iOS和Android应用程序。这些插件可用于设备日志、崩溃报告、检查网络请求、检查应用程序的本地数据库、检查缓存的图像等。

使用Hermes

Hermes是一个专为移动端应用优化的开源javascript引擎。React Native 0.60.4版本之后,Hermes在安卓也可用了。这有利于减少app的下载体积(安卓APK)、降低内存消耗和降低APP的可交互时间

在安卓APP中开启Hermes引擎,需要打开build.gradle并且修改如下:

def enableHermes = project.ext.react.get("enableHermes", true);

自React Native 0.64-rc.0版本后,Hermes也能用于iOS平台。需要打开Podfile并且修改如下:

use_react_native!(:path => config[:reactNativePath], :hermes_enabled => true

不要在源代码中保留console表达式

在Javascript应用包括React Native应用中,用console.log调试是最常用的调试方法之一。然而,在构建React Native应用时,将console语句留在源代码中可能对JavaScript线程造成一些瓶颈。

一个解决方法就是使用babel-plugin-transform-remove-console删除掉console语句。在终端通过下面的方法安装

yarn add babel-plugin-transform-remove-console

然后修改 .babelrc文件如下来删除所有的console语句

{
  "env": {
    "production": {
      "plugins": ["transform-remove-console"]
    }
  }
}

不要使用Scrollview渲染一个大列表数据

有一些方法可以在React Native中使用滚动列表。其中两种最常用的方式就是使用ScrollViewFlatList组件

ScrollView用起来很简单,通常用于使用JavaScript的map()函数遍历一个数组。 例如:

<ScrollView>
  {items.map(item => {
    return <Item key={item.id.toString()} />;
  })}
</ScrollView>

ScrollView会一次性渲染所有的子组件,在需要渲染的子组件数量不多的时候会比较好用。但在处理大量的数据的时候会影响到APP的性能。

为了解决渲染大量数据的情况,React Native提供了一个FlatList组件。这个组件能够懒加载子组件列表,这样APP就不会消耗大量的内存

例如:

<FlatList
  data={elements}
  keyExtractor={item => `${items.id}`}
  renderItem={({ item }) => <Item key={item.id.toString()} />}
/>

结论

React Native是一个用于构建跨平台应用的开源框架。它以JavaScript为核心,并调用原生组件来构建移动端界面和功能。它会是一个高性能框架只要注意考虑到性能

@flytam flytam added the react New feature or request label Mar 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
react New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant