React Performance Optimization

How to optimize React functional components

The following is the edited text


React already uses a number of tricks internally to optimize UI updates and DOM manipulation. In most cases, we don’t need to specifically optimize React performance. Still, here are some ways to speed things up.

Use the production version

React includes many warnings by default to prompt useful feedback during development. But these packets are not small. We must use React in production to deploy packages to the server.

Installing React DevTools will help you determine if you are using a production or development environment.

Virtualization long list

Refer to the react – window

Using this component library, you can easily reduce UI updates in long lists.

React.lazy()

Lazily loaded component

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() = > import('./OtherComponent'));
const AnotherComponent = React.lazy(() = > import('./AnotherComponent'));

function MyComponent() {
    return (
        <div>
            <Suspense fallback={<div>Loading...</div>} ><section>
                    <OtherComponent />
                    <AnotherComponent />
                </section>
            </Suspense>
        </div>
    );
}
Copy the code

Skip the rendering

React uses the diff algorithm to minimize the number of DOM nodes that need to be updated. However, if we know when we don’t need to update the DOM, we can skip rendering by following these methods.

shouldComponentUpdate

The shouldComponentUpdate lifecycle hook function is executed each time the props or state is updated. The default returns true, meaning rendering is required.

By comparing this.props to next-props, this.state to next-state. If the current change in state or props does not require an UPDATE to the DOM, then you can return fasle to avoid unnecessary render and subsequent ComponentDidUpdate execution. (To be honest, are you sure you don’t need to define the state property outside of state??)

React provides the PureComponent by default to build in this functionality. But it only makes a shallow comparison between the value before and after the change. Using extended operator can solve this problem better. (Any method that returns a new object will do, of course).

It is not recommended to do depth comparisons or perform deep clones in shouldComponentUpdate. This will hurt performance.

React.memo()

React. Memo is actually a higher-order component. It takes a component as an argument and returns a new component.

The new component will only re-render the component if its props changes, otherwise the last result in “memory” will be returned directly.

// Child
function Child(props) {
    return <div>{props.name}</div>;
}
Copy the code
// App
class App extends React.Component(a){
    state = {
        title: ' '}; changeTitle =() = > {
        this.setState({
            title: 'i am changed! '}); };render() {
        return (
            <div>
                <span>{this.state.title}</span>
                <button onClick={this.changeTitle}>Click Me</button>
                <Child name="zxl" />
            </div>); }}Copy the code

In the code above, I only changed the title of the parent component, and I did not update the name received by the Child component. But after the title update, not only the App component will be re-rendered, but the Child component will also be re-rendered.

If we want to avoid this, we can use react.Memo ()

function Child(props) {
    return <div>{props.name}</div>;
}

export default React.memo(Child);
Copy the code

By default, the memo only makes shallow comparisons to props. If you want to make a deeper comparison and more precise control, you can pass in a second parameter

React.memo(Child, (preProps, nextProps) = > {});
Copy the code

UseCallback

This Hook is used to skip rendering if a function was passed to Clild. What does that mean?

// Child
function Child(props) {
    return (
        <div>
            <span>{props.name}</span>
            <button onClick={props.changeTitle}>Click Me</button>
        </div>
    );
}

export default React.memo(Child);
Copy the code
// App
class App extends React.Component(a){
    state = {
        title: ' '.subTitle: ' '}; changeTitle =() = > {
        this.setState({
            title: 'i am changed! '}); }; changeSubTitle =() = > {
        this.setState({
            subTitle: 'subTitle Changed! '}); };render() {
        return (
            <div>
                <span>{this.state.title}</span>
                <button onClick={this.changeSubTitle}>Click Me</button>
                <Child name="zxl" changeTitle={this.changeTitle} />
            </div>); }}Copy the code

Whether we change the subTitle when we click the button in the App, or change the title when we click the button in the Child. Triggers the update of the Child. Why is that?

Notice that ChageTitle in our App is the props property of the Child that we passed in. When the App is updated, a new changeTitle function is created. That’s the problem.

UseCallback is designed to solve this problem.

// App
import React, { useCallback } from 'react';
class App extends React.Component(a){
    state = {
        title: ' '.subTitle: ' '}; changeTitle =() = > {
        this.setState({
            title: 'i am changed! '}); }; changeSubTitle =() = > {
        this.setState({
            subTitle: 'subTitle Changed! '}); };render() {
        const memoizedCallback = useCallback(this.changeTitle, []);
        return (
            <div>
                <span>{this.state.title}</span>
                <button onClick={this.changeSubTitle}>Click Me</button>
                <Child name="zxl" changeTitle={memoizedCallback} />
            </div>); }}Copy the code

Reference: useCallback

UseEffect is the second parameter

See skipping Effect for performance tuning

Skip the calculation

useMemo

This hook is used when there is a function that takes a long time to execute and whose value affects the DOM rendering, but is not the only factor. What does that mean?

function Cal() {
    const [count, setCount] = useState(0);
    const longTimeCal = () = > {
        let result = 0;
        for (let i = 0; i < 1000000; i++) {
            result += i;
        }
        return result;
    };
    const value = longTimeCal();
    return (
        <div>
            <span>{count + value}</span>
            <button onClick={(count)= > setCount(count + 1)} />
        </div>
    );
}
Copy the code

The value of this function needs to be evaluated each time it is re-rendered. That’s the problem.

We use useMemo for optimization.

function Cal() {
    const [count, setCount] = useState(0);
    const longTimeCal = () = > {
        let result = 0;
        for (let i = 0; i < 1000000; i++) {
            result += i;
        }
        return result;
    };
    const value = useMemo(longTimeCal, []);
    return (
        <div>
            <span>{count + value}</span>
            <button onClick={(count)= > setCount(count + 1)} />
        </div>
    );
}
Copy the code

The use of the key

Develop good habits

Profiler

React DevTools provides performance analysis tools. See React Profiler for details