Recently, I was writing React-Native and implemented some optimization items while the requirements were almost completed in these two days.

Recorded in the

Life sucks

Performance

See React Native Performance

Check the performance

Open the developer menu (shake the phone to open it) 👉 Open the Show Perf Monitor and you can see the display box below

Both UI and JS frames remain at 60 frames, which is optimal.

JS single thread

All event processing, API requests, etc. are done on this thread, and when this. SetState has a large amount of data, the state change will cause re-render, during which all javascripts controlled animations will get stuck frames

For example, when switching routes, the frame number will have obvious jitter. If you have something to do at componentDidMount it’s going to make the route transition animation very slow. (Some of the solutions you can try are described below

The development environment performs worse than the production environment

In the development environment, the framework has many other operations such as warning error output, type detection, and so on.

If you want to test performance, it’s best to do it in the Release package. It’s more accurate.

Remove console.* from production environment

During development, there are many console.* directives to help with debugging. And some dependent libraries also have console.* These statements can be a huge drain on JavaScript threads. You can remove console.* from production via Babel.

  • Installing a plug-in

    npm i babel-plugin-transform-remove-console --save-dev

  • Configure the. Babelrc file

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

Used when processing large lists of data<FlatList />

The FlatList component is more suitable for displaying long lists and specifies the appropriate getItemLayout method, which skips the layout calculation for rendering items and uses the given configuration directly (see ☝️ for details).

Relying on lazy loading

Before the framework can execute the written business code, the code needs to be loaded and parsed in memory. The larger the code volume, the more time this process takes, resulting in the slow rendering of the first screen. Often, some pages or components are never accessed by the user at all. This can be optimized by lazy loading.

There are examples on the website

VeryExpensive.js

import React, { Component } from 'react';
import { Text } from 'react-native';
// ... import some very expensive modules

// You may want to log at the file level to verify when this is happening
console.log('VeryExpensive component loaded');

export default class VeryExpensive extends Component {
  // lots and lots of code
  render() {
    return <Text>Very Expensive Component</Text>; }}Copy the code

Optimized.js

import React, { Component } from 'react';
import { TouchableOpacity, View, Text } from 'react-native';

let VeryExpensive = null; // Define variables

export default class Optimized extends Component {
  state = { needsExpensive: false }; // Define internal state to control whether the component needs to be loaded

  didPress = (a)= > {
    // When an event that requires a component to be loaded is triggered
    if (VeryExpensive == null) { // Do not repeat references
      VeryExpensive = require('./VeryExpensive').default;  // Assign a reference to the component to the defined variable
    }

    this.setState((a)= > ({
      needsExpensive: true.// Change the state of the control to trigger the component re-render
    }));
  };

  render() {
    return (
      <View style={{ marginTop: 20}} >
        <TouchableOpacity onPress={this.didPress}>
          <Text>Load</Text>
        </TouchableOpacity>
        {this.state.needsExpensive ? <VeryExpensive /> : null}
      </View>); }}Copy the code

Optimize component rendering times

React rerenders components when internal state or externally passed props change. A large number of components that have to be rerendered in a short period of time can cause serious performance problems. There’s a point here that you can optimize.

  • usePureComponentLet components compare themselvespropsIn practice, this controlled approach is more reliable than purely functional components. Or in theComponentThe use ofshouldComponentUpdateMethod to control the updating/re-rendering of components by conditional judgment.
  • usePureComponentNote that this component is in shallow comparison state, ifpropsIf you have a large number of reference type objects, the internal changes of these objects will not be compared. Avoid complex data structures when writing code
  • Fine-grained components, split dynamic/static components. Unified planning is required after the project is stable and has a certain scale.
  • Learning immutable – js * * * *

Asynchronous, callback

JavaScript is single-threaded, taking advantage of its asynchronous nature, and some hook callbacks.

For example, when routing switches occur in componentDidMount, Here can use InteractionManager. RunAfterInteractions () will need to perform operations on runAfterInteractions callback.

componentDidMount() {
	InteractionManager.runAfterInteractions((a)= > {
        // your actions})}Copy the code

Note that the InteractionManager listens for all animations/interactions to complete before triggering callbacks in the runAfterInteractions. If you have long animations or interactions in your project, long waits may occur. Therefore, due to the uncontrollability of InteractionManager, use it according to the actual situation.

Some animation feedback in React-Native, such as TouchableOpacity, will respond to onPress when touched and its transparency will change. If there is complex operation in onPress during this process, it is likely to lead to transparent feedback of the component. You can then wrap the actions in onPress in requestAnimationFrame. Styled – Component Here is my practice (using styled- Component)

import styled from 'styled-components'

export const TouchableOpacity = styled.TouchableOpacity.attrs({
  onPress: props= > () => {
    requestAnimationFrame((a)= > {
      props.onPressAsync && props.onPressAsync()
    }, 0)}})` `
Copy the code

Here we change onPress to perform the onPressAsync incoming operation in the requestAnimationFrame callback.

Similarly, this is done in the onReachEnd of the FlatList to avoid the lag of rolling back in iOS.

Above, some practical optimizations of recent react-native writing are recorded.

The last

The way ahead is so long without ending, yet high and low I’ll search with my will unbending.

May love & peace be with you

reference

  • React native Performance

Author: Roy Luo

React Native Performance Optimization