preface
Because React’s functional components are easy to use (as opposed to the Class component), I’ll focus on using functional components to run development. In this blog series, I’m going to share what I’ve learned about the Hook apis. The Hooks series includes the following:
- useState
- useReducer
- useContext
- useEffect
- useMemo
- useRef
- Customize the Hook
Memo
In the class era, we used to do a shallow comparison of data using pureComponent. With the Hook feature introduced, we could use Memo to improve performance.
But before we do that, let’s do an experiment
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [n, setN] = useState(0);
const [m, setM] = useState(10);
console.log("Execute outermost box.");
return (
<>
<div>Outermost box<Child1 value={n} />
<Child2 value={m} />
<button
onClick={()= > {
setN(n + 1);
}}
>
n+1
</button>
<button
onClick={()= > {
setM(m + 1);
}}
>
m+1
</button>
</div>
</>
);
}
function Child1(props) {
console.log("Executing child component 1");
return <div>N: {props. Value} on child component 1</div>;
}
function Child2(props) {
console.log("Executing child component 2");
return <div>M: {props. Value} on child component 2</div>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Copy the code
In the code above, I set up two child components, respectively read n and M on the parent component, and then set two click buttons on the parent component, when clicked, set n and M plus 1 respectively. Here is the result of the log console when first rendered
Execute the outermost box execute the child component 1 execute the child component 2Copy the code
As imagined, when render, first enter App function, execute, find two child functions inside, execute, create virtual DOM, create entity DOM, and finally render the picture to the page.
Using Memo Optimization
When I click the n+1 button, the n in state must be +1, which will also retrigger the render and update the new n to the view.Let’s go back to the console
Execute outermost box execute subcomponent 1 execute subcomponent 2 + execute outermost box execute subcomponent 1 execute subcomponent 2 + execute subcomponent 1 execute subcomponent 2Copy the code
You’ll notice that subcomponent 2 is also rendered. Obviously React reexecutes all functions, including subcomponent 2 that didn’t have n data.
How to optimize? We can change the subcomponent to the following code using memo
const Child1 = React.memo((props) = > {
console.log("Executing child component 1");
return <div>N: {props. Value} on child component 1</div>;
});
const Child2 = React.memo((props) = > {
console.log("Executing child component 2");
return <div>M: {props. Value} on child component 2</div>;
});
Copy the code
Try clicking again?
I'm going to execute the outermost box I'm going to execute the child component 1 I'm going to execute the child component 2 + I'm going to execute the outermost box + I'm going to execute the child component 1Copy the code
You will notice that no child component 2 is executed
React will only execute the components with the state change, and then use the last memo function if the components have not changed.
bugs
The above code is optimized for performance, but there is a bug
The code above is controlled by the parent component
<Child2 value={m} onClick={addM} />//addM is a function to modify MCopy the code
Click the button to make n+1
I've executed the outermost box I've executed the child component 1 I've executed the child component 2 + I've executed the outermost box + I've executed the child component 1 + I've executed the child component 2Copy the code
Execute child component 2 again.
Why is that? Because App re-executes, it changes the address of the addM function (functions are complex data types), and addM is passed as props to subcomponent 2, which causes the subcomponent 2 function to re-execute.
useMemo
This is where useMemo comes in.
useMemo(()=>{},[])
UseMemo takes two arguments, a function and an array (which is actually a dependency) that contains a return function and an array containing the dependency.
const addM = useMemo(() = > {
return () = > {
setM({ m: m.m + 1 });
};
}, [m]); // Monitors m changes
Copy the code
It is used in the same way as useEffect.
useCallback
The code up there is weird
useMemo(() = > {
return () = > {
setM({ m: m.m + 1 });
};
}, [m])
Copy the code
React gives us syntax candy, useCallback. It reads like this
const addM = useCallback(() = > {
setM({ m: m.m + 1 });
}, [m]);
Copy the code
Doesn’t it look more normal?
The final code
import React, { useCallback, useMemo, useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [n, setN] = useState(0);
const [m, setM] = useState({ m: 1 });
console.log("Execute outermost box.");
const addN = useMemo(() = > {
return () = > {
setN(n + 1);
};
}, [n]);
const addM = useCallback(() = > {
setM({ m: m.m + 1 });
}, [m]);
return (
<>
<div>Outermost box<Child1 value={n} click={addN} />
<Child2 value={m} click={addM} />
<button onClick={addN}>n+1</button>
<button onClick={addM}>m+1</button>
</div>
</>
);
}
const Child1 = React.memo((props) = > {
console.log("Executing child component 1");
return <div>N: {props. Value} on child component 1</div>;
});
const Child2 = React.memo((props) = > {
console.log("Executing child component 2");
return <div>M: {props.value.m} on child component 2</div>;
});
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Copy the code
It is recommended to copy directly to Codesanbox for viewing
conclusion
- use
memo
Can help us optimize the performance of thereact
There is no need to perform unnecessary functions - Passed to a child component because the address of a complex data type may change
props
It’s going to change, and it’s still going to execute unnecessary functions, so it’s going to be useduseMemo
This API useCallback
isuseMemo
The syntactic sugar