React performance optimization prerequisites
React update feature – Child components update with parent components
Because of the hierarchical comparison nature of the React diff algorithm, child components are updated with their parent components by default. Because of this feature, React is prone to performance bottlenecks.
import "./styles.css"; import { useState } from "react"; import Child from "./child"; function App() { const [count, setCount] = useState(false); const [count2, setCount2] = useState(false); return ( <div className="App"> <Child></Child> <button onClick={() => { setCount(! count); }} > count:{count.toString()} </button> <button onClick={() => { setCount2(! count2); }} > count2:{count2.toString()} </button> </div> ); } function Child() { return <div>{Math.random()}</div>; }Copy the code
As you can expect from the code above, the randomness of the button subcomponent changes no matter which button subcomponent is clicked, even if the subcomponent is stateless.
The second memo.
React.memo is an advanced component (that is, it takes functions as arguments). If your component renders the same result with the same props, then you can call it by wrapping it in React. Memo. React.memo only checks for changes in the props. If the changes are made, the props will be re-rendered.
import { memo } from "react";
function Child() {
return <div>{Math.random()}</div>;
}
export default memo(Child);
Copy the code
The above example code is slightly modified to wrap the Child component with React. Memo, which can avoid repeated rendering and achieve certain performance optimization.
3. UseCallback
As we all know, ()=>{} === ()=>{} prints false. Just like the memo attribute declaration, the memo can check for updates to the props, but if the props contain functions, the memo cannot properly determine if the props have changed.
UseCallback returns a Memoized callback function. Passing the inline callback function and the array of dependencies as arguments to useCallback returns the Memoized version of the callback function, which is updated only when a dependency changes. This is useful when you pass callback data to child components that are optimized and use reference equality to avoid unnecessary rendering (such as shouldComponentUpdate).
import "./styles.css"; import { useCallback, useState, memo } from "react"; import Child from "./child"; export default function App() { const [count, setCount] = useState(false); const [count2, setCount2] = useState(false); const onClickChild = useCallback(() => {}, [count]); return ( <div className="App"> <Child onClick={onClickChild}></Child> <button onClick={() => { setCount(! count); }} > count:{count.toString()} </button> <button onClick={() => { setCount2(! count2); }} > count2:{count2.toString()} </button> </div> ); }Copy the code
When button1 is clicked, the count is changed because of the useCallBack binding and the Child is rerendered. Click button2 and the Child does not change at all.
Four useMemo.
Here’s a counterexample:
import "./styles.css"; import { useState } from "react"; import Child from "./child"; export default function App() { const [count, setCount] = useState(false); const [count2, setCount2] = useState(false); const useInfo = { name: "name", count: count }; return ( <div className="App"> <Child useInfo={useInfo}></Child> <button onClick={() => { setCount(! count); }} > count:{count.toString()} </button> <button onClick={() => { setCount2(! count2); }} > count2:{count2.toString()} </button> <div> <input placeholder=" onChange={() => {setCount2(! count2); }} ></input> </div> </div> ); }Copy the code
When the input box enters a value, the Child props does not have anything to do with count2, but the input box is still re-rendered, resulting in unnecessary waste. The useMemo Hook allows you to cache calculations between multiple renders by “remembering” the last one. Optimization with useMemo:
. const useInfo = useMemo( () => ({ count: count, name: "name" }), [count] ); .Copy the code
Conclusion five.
UseMemo and useCallback are not universal performance tuning apis. To be clear, blindly using useMemo and useCallback when the parent component’s rerendering intensity is not high will not optimize, but will lead to negative optimization.
Code base
Codesandbox. IO/s/boring – rh…