我正在try 记住我的ItemCard组件,所以当我调用setItems()时,只有正在更新的ItemCard组件会被重新呈现,这可能吗?

我有一个非常简单的组件,比如:

const ItemList = () => {
  const [items, setItems] = useState([
    { id: 1, count: 5 },
    { id: 2, count: 7 },
    { id: 3, count: 2 },
  ]);

const updateItemCount = (itemId, add) => {
  const updatedItems = items.map((item) => {
    const { id, count } = item;

    if (id === itemId) {
      return { ...item, count: add ? count + 1 : count - 1 };
    }
    return item;
  });

  setItems(updatedItems);
};

  return (
    <div>
      {items.map((item) => (
        <ItemCard {...item} updateItemCount={updateItemCount} />
      ))}
    </div>
  );
};

而ItemCard看起来像是

import { memo } from 'react';

const ItemCard = memo(({id, count, updateItemCount}) => {

console.log("re-rendered", id)

  return (
    <button onClick={() => updateItemCount(id, true)}></button>
  );
});

问题是,当我记录重新渲染时,它们似乎都在单击按钮后重新渲染

推荐答案

您需要将updateItemCount包裹在useCallback中,因为它在每次渲染时都会重新创建,并且memo会看到更改后的props .此外,将key添加到您在map中渲染的每个项目.

如果我们将items数组传递给useCallback个依赖项,则每当items更改时,函数将再次重新创建.为了避免这种情况,在拨打setItems时使用updater function.

const { useState, useCallback, memo } = React;

const ItemList = () => {
  const [items, setItems] = useState(() => [
    { id: 1, count: 5 },
    { id: 2, count: 7 },
    { id: 3, count: 2 },
  ]);
  
  const updateItemCount = useCallback((itemId, add) => {
    setItems(items => items.map(item => {
      const { id, count } = item;

      if (id === itemId) {
        return { ...item, count: add ? count + 1 : count - 1 };
      }
      return item;
    }));
  }, []);

  return (
    <div>
      {items.map((item) => (
        <ItemCard key={item.id} {...item} updateItemCount={updateItemCount} />
      ))}
    </div>
  );
};

const ItemCard = memo(({id, count, updateItemCount}) => {
  console.log(`id update: ${id} - count: ${count}`);
  return (
    <button onClick={() => updateItemCount(id, true)}>{count}</button>
  );
});

ReactDOM
  .createRoot(root)
  .render(<ItemList />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>

Reactjs相关问答推荐

MUImaterial -ui-如何将文本字段和 Select 分组?

Shadck/ui Select -当用户 Select 项目时更改状态

在react中向数组状态添加值时出错

在一个blog函数中调用setState钩子

是否在Extra Reducer完成作业(job)时触发createListenerMiddleware?

如何在React中正确地将密码输入类型切换为文本或反之亦然(下一页)

获取类别和页面的参数

在React Router 6中,在路由渲染后更新路由数据

在添加了useplacesautocomplete后,在构建React/Next.js项目时,NPM抛出类型期望的错误

Zod 验证模式根据另一个数组字段使字段成为必需字段

为什么我的 Next.js (React) 组件只有在页面中时才有效?

改变输入的默认值时出现问题:number react-hook-form

react - 警告:列表中的每个子元素都应该有一个独特的 keys props ,即使我已经设置了 keys

如何在 React 中使用 debounce hooks

使用 Vite 的 React 中的路由无法正常工作(构建中)

如何向 surveyjs 调查添加多个结尾?

React 中的 Slide API Mui 在开始而不是结束时触发侦听器

react-admin useGetIdentity 只返回全名,id 未定义 头像未定义

如何跨微前端 React 应用管理状态管理?

添加禁用的默认选项以 Select