React彻底改变了我们通过其创新和动态的方法构建界面的方式。
自16.8版推出以来,钩子已经变成了游戏规则,使开发人员能够与状态和其他React功能一起工作,而无需上课。
在这些钩子中,有两个脱颖而出的意义:useCallback
和useMemo
。
在本文中,我们将深入研究这些钩子,了解它们的差异,并在,为什么和 >他们应该使用(或不应使用)。
简要介绍USECALLBACK和USEMEMO
useCallback
钩返回回忆版的回调函数,该版本仅在一个依赖项发生变化时会更改。将回调传递给优化的儿童组件时,这很有用,这些组件依靠参考平等来防止不必要的渲染。
useMemo
钩返回了回忆的值。像useCallback
一样,它只有在一个依赖项发生变化时才会重新计算回忆的值。非常适合昂贵的计算。
何时以及如何使用usecallback和usememo
现在我们有了一个简短的理解,让我们跳入一些实际的例子。
复杂的游戏场景 - 使用USECALLBACK
想象我们正在创建一个复杂的游戏应用程序,玩家可以通过收集宝石来提高其水平。每次他们升级时,都会收到一个庆祝信息。这是一个简化的版本。
import React, { useState, useCallback } from 'react';
function Game() {
const [level, setLevel] = useState(1);
const levelUp = () => {
setLevel(level + 1);
};
return <Board level={level} onLevelUp={levelUp} />;
}
function Board({ level, onLevelUp }) {
// A heavy computation function that renders the game board
renderBoard(level);
return (
<div>
<h2>Current Level: {level}</h2>
<button onClick={onLevelUp}>Collect a gem</button>
</div>
);
}
现在,这里的问题是每次Game
渲染时都会创建levelUp
函数。因此,即使没有级别的更改,Board
也会每次重新呈现。这可能会放慢我们的应用程序,尤其是随着复杂的板渲染。这是useCallback
闪耀的地方:
import React, { useState, useCallback } from 'react';
function Game() {
const [level, setLevel] = useState(1);
const levelUp = useCallback(() => {
setLevel(level + 1);
}, [level]);
return <Board level={level} onLevelUp={levelUp} />;
}
随着此更改,除非level
更改,否则回忆的levelUp
函数将传递给Board
。昂贵的板渲染过程只有在必要时才能提高性能。
电子商务过滤器 - 使用USEMEMO
假设您正在构建具有产品清单页面的电子商务应用程序。有一个过滤器功能,允许用户通过其名称搜索产品。这是一个基本设置:
import React, { useState } from 'react';
function ProductList({ products }) {
const [filter, setFilter] = useState('');
const filteredProducts = products.filter(product =>
product.name.toLowerCase().includes(filter.toLowerCase())
);
return (
<>
<input
type="text"
value={filter}
onChange={e => setFilter(e.target.value)}
/>
<ul>
{filteredProducts.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</>
);
}
问题是,filter
函数每次ProductList
渲染都运行。如果您有数千种产品,则可能会大大减慢您的应用程序。 useMemo
钩可以解决这个问题:
import React, { useState, useMemo } from 'react';
function ProductList({ products }) {
const [filter, setFilter] = useState('');
const filteredProducts = useMemo(() =>
products.filter(product =>
product.name.toLowerCase().includes(filter.toLowerCase())
), [products, filter]);
return (
// ...
);
}
现在,昂贵的过滤器功能仅在products
或filter
更改时运行,从而为您的产品列表带来更好的性能。
当不使用usecallback和usememo
尽管useCallback
和useMemo
可以在特定情况下提供性能提升,但不应在任何地方使用它们。这就是原因。
过度使用usecallback
不必要地使用useCallback
会导致弊大于利。它创建了维护该功能的回忆版本的开销,该版本可能比函数调用本身更昂贵。让我们考虑一个例子:
import React, { useState, useCallback } from 'react';
function Greeting() {
const [name, setName] = useState('');
const updateName = useCallback((event) => {
setName(event.target.value);
}, []);
return (
<input
type="text"
value={name}
onChange={updateName}
/>
);
}
在此示例中,不需要useCallback
,因为updateName
函数在计算上不是昂贵的,也不是作为导致不必要的重新订阅者的支架传递的。从此代码中删除useCallback
可以简化它而没有任何性能弊端。
滥用usememo
useMemo
也可能被过度使用或滥用。如果计算在计算上不昂贵,那么useMemo
可能带来的开销比收益更多。例如:
import React, { useMemo } from 'react';
function TotalPrice({ quantity, price }) {
const totalPrice = useMemo(() => quantity * price, [quantity, price]);
return (
<h2>Total Price: {totalPrice}</h2>
);
}
在这种情况下,useMemo
是不必要的,因为乘法操作并不昂贵。最好简单地计算totalPrice
而不记忆:
import React from 'react';
function TotalPrice({ quantity, price }) {
const totalPrice = quantity * price;
return (
<h2>Total Price: {totalPrice}</h2>
);
}
结论
useCallback
和useMemo
是React开发人员工具包中强大的工具。它们旨在通过防止不必要的渲染和计算来帮助优化React应用程序。
但是,像许多强大的工具一样,当不当或过度使用时,它们可能会导致问题。通过了解这些钩子的用例并明智地使用它们,我们可以创建更多的性能和可维护的反应应用程序。