React Performance Optimization — using react Redux

Time:2021-4-18

React rendering mechanism

The previous onearticleI have introduced the rendering mechanism of react

In short, when the page is opened at the beginning, react will call the render function to build a DOM tree. When the state / props changes, the render function will be called again to render another virtula dom. Then, react will compare the two trees, calculate the least modification to the DOM tree, and batch modify it.

Find out the optimization point

Note that if you can judge that the rendering result will not change before rendering the virtual DOM, you can not render and compare the virtual DOM directly, and the speed will be faster.

shouldComponentUpdate

How can it be done?

Here we need to use theshouldComponentUpdateWhen this function returns false, DOM tree does not need to be re rendered directly, thus saving a lot of computing resources.
Because the logic of each react component has its own characteristics, we need to customize the behavior of shouldcomponentupdate function according to the component logic

Take todolist on the official website as an example
http://cn.redux.js.org/docs/b…

import React, { Component, PropTypes } from 'react'

export default class Todo extends Component {
  render() {
    return (
      <li
        onClick={this.props.onClick}
        style={{
          textDecoration: this.props.completed ? 'line-through' : 'none',
          cursor: this.props.completed ? 'default' : 'pointer'
        }}>
        {this.props.text}
      </li>
    )
  }
}

Todo.propTypes = {
  onClick: PropTypes.func.isRequired,
  text: PropTypes.string.isRequired,
  completed: PropTypes.bool.isRequired
}

For this todo, as long as the completed and text remain unchanged, the rendering result of this component will not change. Therefore, shouldcomponentupdate can be written as follows:

shouleComponentUpdate(nextProps, nextState) {
  return (nextProps.completed !== this.props.completed) || 
         (nextProps.text !== this.props.text)
}

Two questions

Next, we need to think about two issues:

  1. Do all components need this shouldcomponentupdate
  2. Is it too cumbersome for each component that needs shouldcomponentupdate to write its own logic

Question 1:

On this issue, I wrote in the previous articlearticleIn fact, it has already been answered and usedReact PrefOrwhy-did-you-updateYou can find components that don’t need to be re rendered. This component is one that needs to be optimized with shouldcomponent update.

Question 2:

It’s really troublesome. If you can be lazy, how can we bear it.
So you can use react Redux directlyconnectHelp us

In fact, connect of react Redux will automatically make an optimization comparison of props. The process is as follows:

React Performance Optimization -- using react Redux

In short, it will get nextprops by various calculations according to the incoming props and state, and compare with a props. If it is not equal, shouldcomponentupdate will return false.

So, with it, todo.js You can write like this

import React, { Component, PropTypes } from 'react'
class Todo extends Component {
  render() {
    return (
      <li
        onClick={this.props.onClick}
        style={{
          textDecoration: this.props.completed ? 'line-through' : 'none',
          cursor: this.props.completed ? 'default' : 'pointer'
        }}>
        {this.props.text}
      </li>
    )
  }
}


Todo.propTypes = {
  onClick: PropTypes.func.isRequired,
  text: PropTypes.string.isRequired,
  completed: PropTypes.bool.isRequired
}

export default connect()(Todo);

tracking problem

Here, I use react pref to track the problem. After that, looking at the console, we can see that the wasted rendering time has changed from todolist to todo to connect (todo) > todo. To understand this phenomenon, we need to understand the implementation of shouldcomponentupdate in connect.

be careful:

React Performance Optimization -- using react Redux

The comparison of props here is only a shallow comparison, so to make react Redux think that the front and back objects are the same, it must point to the same JS object.

For example:

<Foo style={color: 'red'}>

In this way, every time the style is passed in, it is a new object, so even if the values in it are equal, the shallow comparison of react Redux still thinks that it does not need to be re rendered.

Come back and see how todo is used in todolist

 <ul>
    {this.props.todos.map((todo, index) =>
      <Todo {...todo}
            key={index}
            onClick={() => this.props.onTodoClick(index)} />
    )}
 </ul>

I don’t know if you have found out? Every one hereonClickIs a new function, even ifTodoIt’s armedshouldComponentUpdateThe realization of shallow comparisonpropsAlways not equal, still can not avoid every update will be re rendered fate.

How to improve

There are two approaches:

Method 1

First, let’s see how the ontodoclick is passed down layer by layer

// App.js
<TodoList
  todos={visibleTodos}
  onTodoClick={index =>
  dispatch(toggleTodo(index))}
/>

// TodoList.js
 <Todo {...todo}
   key={index}
   onClick={() => this.props.onTodoClick(index)}
/>

//todo.js
 <li
    onClick={this.props.onClick}
    style={{
      textDecoration: this.props.completed ? 'line-through' : 'none',
      cursor: this.props.completed ? 'default' : 'pointer'
    }}>
    {this.props.text}
  </li>
       

In todolist, you can pass ontodoclick directly without constructing an anonymous function, and then index can be placed in the newly added attribute index.

// TodoList.js
 <Todo {...todo}
   key={index}
   *id={item.id}*
   onClick={onTodoClick}
/>

// todo.js Mapdispatchtoprops needs to be changed accordingly

const mapDispatchToProps = (dispatch, ownProps) => ({
  onClick: () => ownProps.onToggle(ownProps.id)
})

Method 2
Let todolist not pass any function type prop to todo directly. The click event is completely handled by the todo component itself.

//Todolist just needs to wear an ID
 <Todo {...todo}
   key={index}
   *id={item.id}*
/>

//In todo, you can distribute action through react redux

const mapDispatchToProps = (dispatch, ownProps) => {
  const {id} = this.props;
  return {
    onClick: () => dispatch(toggleTodo(id))
  }
}

Comparing the two methods, in fact, for todo, you need to use react Redux, and you need todolist to pass in an ID. the only difference is whether the actions are imported by the parent component or by the component itself.

In contrast, there is no need to pass the action layer by layer. The second way is to let todo handle all his own affairs, which is more in line with the requirements of high cohesion.

summary

All in all, we need to find the components that need to be optimized through react pref, and then use connect to help us optimize.

reference resources:
“React and Redux in simple terms” — Cheng Mo

Recommended Today

Review of SQL Sever basic command

catalogue preface Installation of virtual machine Commands and operations Basic command syntax Case sensitive SQL keyword and function name Column and Index Names alias Too long to see? Space Database connection Connection of SSMS Connection of command line Database operation establish delete constraint integrity constraint Common constraints NOT NULL UNIQUE PRIMARY KEY FOREIGN KEY DEFAULT […]