memo
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
const ChildComponent = () =>{
return (
<>
{console.log('子组件渲染')}
<span>子组件</span>
</>
)
}
const ParentComponent = () => {
const [count, setCount] = useState(0);
return (
<>
<h1>{count}</h1>
<button onClick={e => setCount(c => c + 1)}>+1</button>
<ChildComponent />
</>
)
}
ReactDOM.render(<ParentComponent />, document.getElementById('root'));
定义了一个子组件,定义了一个父组件,我们希望在父组件count值变化的时候子组件不必重新渲染,但是发现在点击按钮的时候console.log会被执行:
为了避免这种情况,可以在子组件外部包一个memo,memo会对props进行浅层比较。
const ChildComponent = memo(() =>{
return (
<>
{console.log('子组件渲染')}
<span>子组件</span>
</>
)
})
useCallback
现在向子组件传递一个函数
import React, {useState, memo} from 'react';
import ReactDOM from 'react-dom';
const ChildComponent = memo(() =>{
return (
<>
{console.log('子组件渲染')}
<span>子组件</span>
</>
)
})
const ParentComponent = () => {
const [count, setCount] = useState(0);
const fn = () => {
console.log(1);
}
return (
<>
<h1>{count}</h1>
<button onClick={e => setCount(c => c + 1)}>+1</button>
<ChildComponent fn={fn}/>
</>
)
}
ReactDOM.render(<ParentComponent />, document.getElementById('root'));
这时候我们发现虽然用memo包裹了子组件,但是点击+1以后仍然会重新渲染子组件,这是因为在点击+1时,父组件会重新执行,这样每次fn都会发生变化,传递给子组件的函数也就发生了变化。因此子组件会重新执行,但是我们不希望子组件重新执行,那么传递给fn的函数也不应该发生变化。
import React, {useState, memo, useCallback} from 'react';
import ReactDOM from 'react-dom';
const ChildComponent = memo(() =>{
return (
<>
{console.log('子组件渲染')}
<span>子组件</span>
</>
)
})
const ParentComponent = () => {
const [count, setCount] = useState(0);
const fn = useCallback(() => {
console.log(1);
}, [])
return (
<>
<h1>{count}</h1>
<button onClick={e => setCount(c => c + 1)}>+1</button>
<ChildComponent fn={fn}/>
</>
)
}
ReactDOM.render(<ParentComponent />, document.getElementById('root'));
useCallback后面是依赖项,如果依赖项发生了改变函数才会重新变化。
useMemo
现在修改一下父组件
import React, {useState, memo, useCallback} from 'react';
import ReactDOM from 'react-dom';
const ChildComponent = memo(() =>{
return (
<>
{console.log('子组件渲染')}
<span>子组件</span>
</>
)
})
const ParentComponent = () => {
const [count, setCount] = useState(0);
const fn = useCallback(() => {
console.log(1);
}, [])
const fn2 = () => {
console.log('fn2执行');
let temp = 0;
for (let i = 0; i < 100; i++) {
temp += i;
}
return temp;
}
fn2()
return (
<>
<h1>{count}</h1>
<button onClick={e => setCount(c => c + 1)}>+1</button>
<ChildComponent fn={fn}/>
</>
)
}
ReactDOM.render(<ParentComponent />, document.getElementById('root'));
每次更新count的时候父组件都会被重新执行,那么每次fn2都要被重新计算一次,这时候就可以用useMemo来进行优化,返回一个memorized的值
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
import React, {useState, memo, useCallback, useMemo} from 'react';
import ReactDOM from 'react-dom';
const ChildComponent = memo(() =>{
return (
<>
{console.log('子组件渲染')}
<span>子组件</span>
</>
)
})
const ParentComponent = () => {
const [count, setCount] = useState(0);
const fn = useCallback(() => {
console.log(1);
}, [])
const fn2 = () => {
console.log('fn2执行');
let temp = 0;
for (let i = 0; i < 100; i++) {
temp += i;
}
return temp;
}
const memorizedValue = useMemo(() => fn2(), [])
return (
<>
<h1>{count}</h1>
<button onClick={e => setCount(c => c + 1)}>+1</button>
<ChildComponent fn={fn}/>
</>
)
}
ReactDOM.render(<ParentComponent />, document.getElementById('root'));