React Hooks的useMemo到底有什么用
useMemo
是React提供的一个用于优化性能的Hook,它的作用是用来缓存计算结果,避免重复计算。可以将一些昂贵的计算操作放到useMemo
函数中,这样只有在依赖项发生变化时才会重新计算,从而提高应用程序的性能。
1-useMemo
的语法
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
其中,第一个参数是一个函数,用于执行昂贵的计算操作,第二个参数是一个数组,包含了所有的依赖项。当依赖项发生变化时,useMemo
函数会重新计算值,否则它会返回缓存的值。
2-useMemo
函数缓存计算结果
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [factorial, setFactorial] = useState(1);
const calculateFactorial = (number) => {
let result = 1;
for (let i = 1; i <= number; i++) {
result *= i;
}
return result;
};
const memoizedFactorial = useMemo(() => calculateFactorial(count), [count]);
const handleIncrement = () => {
setCount(count + 1);
};
const handleCalculateFactorial = () => {
setFactorial(memoizedFactorial);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
<p>Factorial: {factorial}</p>
<button onClick={handleCalculateFactorial}>Calculate Factorial</button>
</div>
);
}
export default App;
在上面的代码中,我们定义了一个计算阶乘的函数calculateFactorial
,它用于计算当前计数器的阶乘。然后,我们在useMemo
函数中调用该函数,将计算结果缓存起来。每当计数器的值发生变化时,useMemo
函数会重新计算阶乘,并将计算结果缓存起来。然后,我们在点击“Calculate Factorial”按钮时,将缓存的阶乘值设置为当前的阶乘值。这样就可以避免重复计算,提高应用程序的性能。
3-什么情况下用useMemo包裹整个组件
在某些特殊情况下,如果组件中所有的状态都是由父组件传递而来,并且这些状态的传递是非常频繁的,那么可以考虑将整个组件用useMemo
包裹,以避免不必要的重渲染。
例如,如果父组件传递了一个非常庞大的对象作为 props,而这个对象的每个属性都会被组件使用,那么可以将整个组件用useMemo
包裹,以避免在每次渲染时都重新计算该对象。
import React, { useMemo } from 'react';
function MyComponent({ data }) {
const memoizedData = useMemo(() => data, [data]);
return (
<div>
<p>Name: {memoizedData.name}</p>
<p>Age: {memoizedData.age}</p>
<p>Address: {memoizedData.address}</p>
</div>
);
}
export default useMemo(MyComponent);
在上面的代码中,我们将MyComponent
组件用useMemo
包裹,并将data
作为依赖项传递给useMemo
函数。这样,当data
发生变化时,MyComponent
组件才会重新渲染,否则它会保持不变。
总的来说,使用useMemo
包裹整个组件是一种比较特殊的情况,需要谨慎使用。通常情况下,应该尽量将useMemo
的作用范围限制在局部变量或者函数中,以便更好地优化组件的性能。
4-反面案例
当使用useMemo
的时候,需要注意以下几点,否则可能会出现错误的使用方式:
4.1-使用useMemo
来优化简单的计算操作
例如简单的加减乘除运算,这样会增加代码的复杂度,反而会降低性能。
import React, { useMemo } from 'react';
function App() {
const a = 10;
const b = 20;
const memoizedSum = useMemo(() => a + b, [a, b]);
return (
<div>
<p>Sum: {memoizedSum}</p>
</div>
);
}
export default App;
4.2-将useMemo
用于副作用操作
例如修改DOM或者发送网络请求等操作,这些操作应该放在useEffect
中进行。
import React, { useMemo } from 'react';
function App() {
const memoizedMessage = useMemo(() => {
const message = 'Hello world';
document.title = message;
return message;
}, []);
return (
<div>
<p>{memoizedMessage}</p>
</div>
);
}
export default App;
4.3-将整个组件用useMemo
包裹
这样会导致组件的所有状态都被缓存,当任何一个状态改变时,整个组件都需要重新渲染,反而会降低性能。
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const memoizedState = useMemo(() => {
return { count, setCount };
}, [count, setCount]);
const handleIncrement = () => {
memoizedState.setCount(memoizedState.count + 1);
};
return (
<div>
<p>Count: {memoizedState.count}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
export default useMemo(App);
4.4-混用useMemo
和useCallback
它们虽然都可以用于缓存计算结果,但是它们的作用不同,useMemo
用于缓存值,useCallback
用于缓存函数。
import React, { useState, useMemo, useCallback } from 'react';
function App() {
const [count, setCount] = useState(0);
const memoizedValue = useMemo(() => {
return count * 2;
}, [count]);
const memoizedFunction = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>Value: {memoizedValue}</p>
<button onClick={memoizedFunction}>Increment</button>
</div>
);
}
export default App;
总的来说,需要遵循useMemo
的使用规范,避免出现上述错误的使用方式,以确保代码的正确性和性能的优化。
原文链接:https://juejin.cn/post/7216942649067585593 作者:星辰_Stars