preface
When developing React, we often encounter the situation that the parent component introduces the child component. When no optimization is done, the child component is often rendered unnecessarily repeatedly. Look at a simple example
Example 1: In this case, every time the parent updates the count value, the child component repeats the rendering
function Child(props){
console.log('Subcomponent Render')
return(
<div>{props.title}</div>)}function Parent(){
const [count, setCount] = useState(1);
return(
<div>
<Child title="I am a child component" />
<button onClick={()= > setCount(count+1)}>add</button>
<div>count:{count}</div>
</div>)}Copy the code
React.memo
React.memo is a higher-order component, which is similar to the react. PureComponent
React.memo(component, Func), the first argument is a custom component, and the second argument is a function to determine if the component needs to be re-rendered. If the second parameter is omitted, the default is a shallow comparison of the props of the component
// Modify example 1: In this case, the props of the Child are not changed, so the render is not repeated
function Child(props){
console.log('Subcomponent Render')
return(
<div>{props.title}</div>)}const NewChild = React.memo(Child, (prevProps, nextProps) = > {
// A custom comparison method can also be ignored
// return true does not re-render
// return false to re-render
})
function Parent(){
const [count, setCount] = useState(1);
return(
<div>
<NewChild title="I am a child component" />
<button onClick={()= > setCount(count+1)}>add</button>
<div>count:{count}</div>
</div>)}Copy the code
However, in some cases, the react. Memo is wrapped around the subcomponents, and the subcomponents still do unnecessary repeated rendering updates, where useMemo and useCallback can be used for more granular performance optimization. Look at this example
2 / / examples
function Child({title, onChangeTitle}){
console.log('Subcomponent Render')
return(
<>
<div>{title.value}</div>
<button onClick={()= >OnChangeTitle (' I am the new title')}>change title</button>
</>)}constNewChild = React. Memo (Child);function Parent(){
const [count, setCount] = useState(1);
const [title, setTitle] = useState('I'm a child component');
const onChangeTitle = (text) = > {
setTitle(text)
}
return(
<div>
<NewChild title={{value: title}} onChangeTitle={onChangeTitle}>
<button onClick={()= > setCount(count+1)}>add</button>
<div>count:{count}</div>
</div>)}Copy the code
In this case, each time the parent component updates, the title and onChangeTitle values of the child component generate a new memory address, so even if the title does not change, the child component is rerendered, and the memo is invalid
useMemo
Executed on the first rendering, the variables are cached and then recalculated only when the dependency changes
useCallback
The function is cached the first time it is rendered, and then the cache is updated only when a dependency changes
// modify example 2
function Child({title, onChangeTitle}){
console.log('Subcomponent Render')
return(
<>
<div>{title.value}</div>
<button onClick={()= >OnChangeTitle (' I am the new title')}>change title</button>
</>)}constNewChild = React. Memo (Child);function Parent(){
const [count, setCount] = useState(1);
const [title, setTitle] = useState('I'm a child component');
const onChangeTitle = useCallback((text) = > {
setTitle(text)
},[])
const memoTitle = useMemo(() = > ({value: title}), [title])
return(
<div>
<NewChild title={memoTitle} onChangeTitle={onChangeTitle} />
<button onClick={()= > setCount(count+1)}>add</button>
<div>count:{count}</div>
</div>)}Copy the code
conclusion
UseMemo and useCallback are used in the same way. They are both executed on the first rendering and again when a dependency changes. The difference is that useMemo returns cached variables and useCallback returns cached functions
In the actual business component development process, it will be much more complex than the above example, so there will be many factors that cause unnecessary repeated rendering. We need to use React. Memo, useMemo, and useCallback to optimize the components, but do not blindly use them