It’s been a long time since I’ve shared an update, and I’ve been boiling a frog in warm water. Due to some reasons and the fact that the society is really too volumed, I was forced to join the inner voluming army and review a lot of knowledge. At the same time, I also found a lot of shortcomings in myself. I also want to take this opportunity to let everyone to voluming, after all, the ability is my own.
The original link

The first word

You can actually learn most of what I wanted to write today on the React official document. So why do I want to write? As a person who has been writing React for almost three years, I have not read the official documents seriously. I would like to tell people who are similar to me, and add some of my own understanding and opinions.

Let me ask you a few questions

Performance optimization of the problem, is really never can’t escape, is a the interviewer will ask a few words, but to be honest I don’t know is made of the React too good, or I do projects too basis, basic didn’t meet any performance problems, cause I don’t know for a long period of time the React and many related to performance optimization of API.

Let’s take a look at the code, I directly define multiple components in a file for everyone to see, formally write code when a file is a component.

import React from 'react'; class Test extends React.Component { componentDidUpdate() { console.log('Test componentDidUpdate'); } render() { return <div></div>; } } export default class App extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState((state) => ({ count: state.count + 1, })); } handleTestClick() {} render() { return ( <div> <div>{this.state.count}</div> <div onClick={this.handleClick}>click</div> <Test onClick={this.handleTestClick} /> </div> ); }}

This code has nothing to say, every time click update state, I am going to ask a few questions, you first think about ~

  1. Each clickclickThe time,TestThe component will printTest componentDidUpdate?
  2. If I hadTestThe component’sReact.ComponentReplace withReact.PureComponent, are the results the same as above? If not, why not?
  3. So if I change this line of code<Test onClick={this.handleTestClick} />for<Test onClick={() => {}} />And the results?

shouldComponentUpdate

ShouldComponentUpdate is part of the React lifecycle, and most React developers have at least heard of it. Basically, this function returns a Boolean value that React uses to determine whether a component needs to be re-rendered.ShouldComponentUpdate is a function that shouldComponentUpdate is part of the React lifecycle, and most React developers have at least heard of it.

ShouldComponentUpdate receives two props and an updated state. You can compare the two props and state to determine if the component needs to be re-rendered.

import React from 'react'; class Test extends React.Component { componentDidUpdate() { console.log('Test componentDidUpdate'); } // Test ComponentDidUpdate will be printed every time I click // Test ComponentDidUpdate will not be printed if the count is unchanged shouldComponentUpdate(nextProps) { if (this.props.count === nextProps.count) { return false; } return true; } render() { return <div></div>; } } export default class App extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState((state) => ({ count: state.count, })); } render() { return ( <div> <div>{this.state.count}</div> <div onClick={this.handleClick}>click</div> <Test count={this.state.count} /> </div> ); }}

This code is also a little bit more intuitive for shouldComponentUpdate, why do we do that? When there’s only one Test component, it doesn’t matter much, but when there are a thousand or even ten thousand Tests, and every click there are a thousand or ten thousand Tests componentDidUpdate being called, that’s a bit of an exaggeration. Be aware of this when using looping render components, as it can become a bottleneck in your application.

Now let’s solve the first problem. Does the Test component print Test ComponentDidUpdate every time I click?

Yes, the Test component will print Test ComponentDidUpdate every time we click, unless we define a shouldComponentUpdate in Test and return false to prevent it from re-rendering.

PureComponent

Component is similar to PureComponent, but the difference between them is that PureComponent implements shouldComponentUpdate. That’s why I said we should start with shouldComponentUpdate.

import React from 'react'; class Test extends React.PureComponent { componentDidUpdate() { console.log('Test componentDidUpdate'); } shouldComponentUpdate(props) {if (this.props. Count === props. Count) {return false; } return true; } render() { return <div></div>; }}

If you use shouldComponentUpdate again in PureComponent you should get a warning, and the profile also tells us that PureComponent already implements shouldComponentUpdate.

Test has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.

PureComponent implements this function as a shallow comparison of props and states. What is a shallow comparison? A == B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B = B

let a = 5;
let b = 5;
let c = {};
let d = {};
console.log(a === b); // true
console.log(c === d); // false

When looking at a problem caused by bad code, it is important to pay attention to this section.

import React from 'react'; Class Test extends React.PureComponent {// render the animal from the App every time you click on the App to add a new animal. Dog render() {return <div>Test: {this.props.animal.join(',')}</div>; } } export default class App extends React.Component { constructor(props) { super(props); This. state = {Animal: ['dog']}; this.handleClick = this.handleClick.bind(this); } // Add a new value to Animal each time you click // There is a Bug here, since the Animal.push method updates the original array // but they are still an array (this is a bit weird), The pointer is still the same // It may be necessary for the reader to search and understand how primitive and reference types are stored in JS // So when the Test component receives a new Animal, Test does not re-render handleClick(val) {const {Animal} = this.state; animal.push(val) this.setState({ animal, }); } // State Animal render() {return (<div> <div>App: {this.state.animal.join(',')}</div> <div onClick={() => this.handleClick('cat')}>click</div> <Test animal={this.state.animal} /> </div> ); }}

You should be able to answer the second and third questions, but let’s take a look again

Q: If I replace the React.Component in the Test component with React.PureComponent, will the result be the same as above? If not, why not?

A: Because the onClick in the props is the handleTestClick in the App component and the pureComponent is used, so each shallow comparison is consistent, so the Test ComponentDidUpdate will not be printed.

=

{}} />

A: Although PureComponent is used, each click will still print the Test ComponentDidUpdate because the App will re-declare a method every time it calls the render function, which is different from the method passed to Test last time.

The rest of the content to supplement

With the exception of the two above, the other APIs are more or less modifications of them, so I’ll put them all together.

memo

React. Memo in my opinion is the stateless version of PureComponent. If you use a class, you use PureComponent and if you use a stateless component, you use memo.

import React from 'react'; export default React.memo(function Test() { return <div>Test Component</div>; }); // This function functions the same functions as the last function, as well as the current function. // This function functions the same functions as the last function, as well as the current function

Note: This method returns the opposite value of shouldComponentUpdate. It does not re-render the component if it returns true.

UseCallback and useMemo

These two APIs are part of the React Hook. Why do we say them together? Because they are very similar, useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

As a result of React Hook, I seldom write class components anymore, and the reason why is clear to those who have used it. This article will not cover that. I just want to ask you one more question: Does the Handleclick method get redefined every time?

import React from 'react';

export default function Test() {
  const handleClick = () => console.log('click');
  return <div onClick={handleClick}>Test</div>
}

The answer is yes, you can check it out.

import React, { useState } from 'react'; // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set let set = new Set(); export default function App() { const [val, setVal] = useState(0); // const handleClick = useCallback(() => console.log('click'), []); const handleClick = () => console.log('click'); Set. Add (HandleClick); Set. Add (HandleClick); console.log(set.size); Return (<div> {/* If Test is a particularly complex component, */} <Test onClick={handleClick}>Test</Test> <div onClick={() => setVal(val + 1)}>click</div> </div> ); }

Usage and instructions can be seen from the above example, without additional explanation. Sometimes we need to cache a value in addition to a function, and then we need to use UseMemo. That’s the difference between the two. See usage directly.

import React, { useState, useMemo } from 'react'; let set = new Set(); export default function App() { const [val, setVal] = useState(0); / / contrast three ways as you can see the difference between / / const obj = useMemo (() = > ({label: 'Test' value: 'Test'}), []); // const obj = 'obj'; const obj = { label: 'Test', value: 'test' }; set.add(obj); console.log(set.size); Return (<div> {/* If Test is a particularly complex component, */} <Test obj={obj}>Test</Test> <div onClick={() => setVal(val + 1)}>click</div> </div>); }

This again involves the distinction between a base type and a reference type in JavaScript. Similar to the above comparison, you can try the effect when obj equals a base type.

Profiler

Last but not least, profilers are used to measure the overhead associated with rendering DOM trees wrapped around them. They can help you detect performance bottlenecks and see usage directly.

import React, { Profiler, useState } from 'react'; function Test() { return <div>Test</div>; } const callback = (id, // One of the "id" phases of the committed Profiler tree occurs, // "mount" (if the component tree has just been loaded) or "update" (if it has been rerendered) actualDuration, // The updated rendering time taken by committed is baseDuration. // The time startTime required to render the entire subtree without memoization is estimated. // commitTime on React start rendering // React committed time interactions in this update // Set of interactions in this update) => {console.log(ID, phase, actualDuration, baseDuration, startTime, commitTime, interactions ); }; export default function App() { const [val, setVal] = useState(0); return ( <div> <Profiler id="test" onRender={callback}> <Test>Test</Test> </Profiler> <div onClick={() => setVal(val + 1)}>click</div> </div> ); }

The last of all

The React API that I know about performance tuning is on there, and to be honest, we don’t see that many performance tuning scenarios. That’s why interviewers often ask about it, because most people don’t pay attention to it, and we want that few people. So, learn more knowledge is really good for yourself, understand more content, you can better understand other people’s code.