React中的每一个状态变化都会导致重新渲染,这可能会对应用程序产生严重的影响。主要是当组件尺寸增加时。useCallback 和useMemo 钩子被用来提高React应用程序的性能。
useCallback和useMemo做的是同一件事吗?
虽然两者都是用于性能优化,但对于开发者来说,他们可能会对他们的使用情况感到困惑。 因此,让我们彻底了解他们。
在深入了解它们的区别之前,让我们先了解一下它们被使用的原因。
- 如上所述,这两个钩子都是用于性能优化的。
- 如果我们的应用程序经常进行重新渲染,那么根据使用情况,我们可以使用其中之一。
让我们看看它们在语法上有什么不同。
useCallback(()=>{
doSomething();
}, [dependencies]);
useMemo(()=>{
doSomething();
}, [dependencies]);
正如我们所看到的,除了命名之外,它们在语法上没有任何区别。 两个钩子都接受一个函数和一个依赖数组。
useMemo与useCallback有什么不同?
useMemo和useCallback钩子的主要区别是,useMemo ,返回记忆化的值,而useCallback ,返回记忆化的函数。
还在困惑吗? 没问题。我们将通过一个例子来了解两者的区别。
假设我们有一个父组件。
import { React, useState } from 'react';
import ChildComponent from './ChildComponent'
function App() {
const [num, setNum] = useState(0);
return(
<div>
<h1>{num}</h1>
<ChildComponent />
<button onClick={() => setNum(num + 1)}> Addition </button>
</div>
);
}
和一个子组件
import { React } from 'react';
function ChildComponent() {
console.log("child component rendered")
return(
<div>
<h1>Hello World</h1>
</div>
);
}
export default ChildComponent;
我们可以观察到,每次我们点击Addition 按钮时,都会打印控制台语句--child component rendered 。
尽管状态变化只发生在父组件中,但子组件却在不必要地重新渲染。
让我们来看看如何避免这种情况。
了解useMemo
在这种情况下,useMemo 可以给我们提供备忘的结果。只需用useMemo 包装来调用子组件。
所以,父组件会看起来像。
import { React, useState, useMemo } from 'react';
import ChildComponent from './ChildComponent'
function App() {
const [num, setNum] = useState(0);
const getChildComp = useMemo(() => <ChildComponent />, []);
return(
<div>
<h1>{num}</h1>
{getChildComp}
<button onClick={() => setNum(num + 1)}> Addition </button>
</div>
);
}
我们可以观察到在这里,当我们点击Addition 按钮时,控制台语句不会被打印出来。
因此,在这种情况下,useMemo 帮助我们提高了性能。
现在,让我们看看useCallback 是如何工作的。
了解useCallback
只要在父组件中创建一个函数,并将其传递给子组件。 这样,父组件就会看起来像。
import { React, useState } from 'react';
import ChildComponent from './ChildComponent'
function App() {
const [num, setNum] = useState(0);
const handleUpdateNum = () => {
//some code
};
const getChildComp = useMemo(
() => <ChildComponent handleUpdateNum={handleUpdateNum} />,
[handleUpdateNum]
);
return(
<div>
<h1>{num}</h1>
{getChildComp}
<button onClick={() => setNum(num + 1)}> Addition </button>
</div>
);
}
现在,如果我们试图点击Addition 按钮,我们可以在控制台看到child component rendered 。所以,在这种情况下,useMemo 不会有帮助。
因为每当父组件被重新渲染时,handleUpdateNum 函数就会被重新创建。
这时,useCallback 出现了,它为我们返回记忆化的函数。
让我们用useCallback 钩子包裹handleUpdateNum函数,看看结果。因此,父组件的代码将看起来像这样。
import { React, useState, useCallback } from 'react';
import ChildComponent from './ChildComponent'
function App() {
const [num, setNum] = useState(0);
const handleUpdateNum = useCallback(() => {
//some code
}, []);
const getChildComp = useMemo(
() => <ChildComponent handleUpdateNum={handleUpdateNum} />,
[handleUpdateNum]
);
return(
<div>
<h1>{num}</h1>
{getChildComp}
<button onClick={() => setNum(num + 1)}> Addition </button>
</div>
);
}
现在我们可以看到,即使在父组件的状态发生变化后,子组件也没有重新渲染。
总结
虽然我们已经探讨了useCallback 和useMemo ,但我们可以根据自己的需求来使用这些钩子。 只需将这些钩子视为React中的微调。 它不能修复写得不好的代码,但如果一切都符合要求,这些钩子将提供其额外的好处。