useCallback和useMeme具体使⽤场景介绍
⼀、先说⼀下react
react是基于数据是不可变的(每次setState都会返回⼀个新数据),这也是为什么需要setState()来更新数据⽽不能使⽤像vue的this.state = newState的形式更新数据的原因,其实你⽤this.state=newState确实可以改数据,但是react不知道数据变了。
⼆、useMemo、useEffect的执⾏时机对⽐
useMemo和useCallback都会在组件第⼀次渲染的时候执⾏,之后会在其依赖的变量发⽣改变时再次执⾏;并且这两个hooks都返回缓存的值,useMemo返回缓存的变量,useCallback返回缓存的函数。
三、useMemo的使⽤场景
使⽤过vue的话,你可以把它理解成vue⾥⾯的computed,是⼀种数据的缓存,⽽这个缓存依赖后⾯的第⼆个参数数组,如果这个数组⾥⾯传⼊的数据不变,那么这个useMemo返回的数据是之前⾥⾯return的数据。
在具体项⽬中,如果你的页⾯上展⽰的数据是通过某个(某些)state计算得来的⼀个数据,那么你每次这
个组件⾥⾯⽆关的state变化引起的重新渲染,都会去计算⼀下这个数据,这时候就需要⽤useMemo(()=>{}, [])去包裹你的计算的⽅法体,这样那些⽆关的state改变引起的渲染不会重新计算这个⽅法体,⽽是返回之前计算的结果,达到⼀种缓存的效果。
export default function WithMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
const expensive = useMemo(() => {
console.log('compute');
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}, [count]);
return <div>
<h4>{count}-{expensive}</h4>
{val}
<div>
<button onClick={() => setCount(count + 1)}>+c1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
}
四、useCallback使⽤场景
useCallback跟useMemo⽐较类似,但它返回的是缓存的函数。
hooks组件state改变后会引起⽗组件的重新渲染,⽽每次重新渲染都会⽣成⼀个新函数,所以react⼦组件props在浅⽐较的时候就会认为props改变了,引起⼦组件不必要的渲染。
使⽤场景是:有⼀个⽗组件,其中包含⼦组件,⼦组件接收⼀个函数作为props;通常⽽⾔,如果⽗组件更新了,⼦组件也会执⾏更新;但是⼤多数场景下,更新是没有必要的,我们可以借助useCallback来返回函数,然后把这个函数作为props传递给⼦组件;这样,⼦组件就能避免不必要的更新。
为什么useCallback需要配合来使⽤?
react的Hooks组件对props的浅⽐较是在memo⾥⾯⽐较的(类组件是在shouldComponentUpdate⾥⾯),如果没有memo,那么你使⽤useCallback就没啥意义,反⽽浪费性能(因为useCallback来包裹函数也是需要开销的)。因为⼦组件还是会重新渲染。
function APP() {
const [value, setValue] = useState(123)
const [otherValue, setOtherValue] = useState(999)
const changeValue = useCallback(() => {
setValue(value => value+1)
}, [])
console.log('APP');
return (
<div>
<div>与Message渲染⽆关的数据==={otherValue}</div>
<br />
<button onClick={() => setOtherValue(value => value-=5)}>改变⽆关的数据</button>reacthooks理解
<br />
<br />
<Message value={value} changeValue={changeValue} />
</div>
)
}
const Message = memo(
function Message({value, changeValue}) {
console.log('Message');
return (
<div>
<button onClick={changeValue}>改变有关数据</button>
<p>与Message渲染有关的数据{value}</p>
</div>
)
}
)