了解Usecallback和Usememo之间的差异
#javascript #网络开发人员 #react #hooks

React彻底改变了我们通过其创新和动态的方法构建界面的方式。

自16.8版推出以来,钩子已经变成了游戏规则,使开发人员能够与状态和其他React功能一起工作,而无需上课。

在这些钩子中,有两个脱颖而出的意义:useCallbackuseMemo

在本文中,我们将深入研究这些钩子,了解它们的差异,并在,为什么 >他们应该使用(或不应使用)。

简要介绍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 (
    // ...
  );
}

现在,昂贵的过滤器功能仅在productsfilter更改时运行,从而为您的产品列表带来更好的性能。

当不使用usecallback和usememo

尽管useCallbackuseMemo可以在特定情况下提供性能提升,但不应在任何地方使用它们。这就是原因。

过度使用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>
  );
}

结论

useCallbackuseMemo是React开发人员工具包中强大的工具。它们旨在通过防止不必要的渲染和计算来帮助优化React应用程序。

但是,像许多强大的工具一样,当不当或过度使用时,它们可能会导致问题。通过了解这些钩子的用例并明智地使用它们,我们可以创建更多的性能和可维护的反应应用程序。