首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在React中编辑对象数组?

如何在React中编辑对象数组?
EN

Stack Overflow用户
提问于 2022-11-21 19:20:28
回答 2查看 42关注 0票数 0

假设我有一个react状态变量,它是一个用户对象数组。用户对象有两个对我们很重要的键: id和name。我必须更改该列表中两个用户的名称。此代码如下

`

代码语言:javascript
运行
复制
const App = () => {
  
  const [users, setUsers] = useState([]);
  
  useEffect(async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    const users = await response.json();
    setUsers(users);
  }, [])
  
  const edit1 = (id) => {
    const newUsers = users.map(user => {
      if(user.id === id) {
        user.name = 'John Doe';
      } 
      return user;
    });    
    setUsers(newUsers);
  }
  
  const edit2 = (id) => {
    const newUsers = users.map(user => ({
      ...user,
      name: user.id === id ? 'Jane Doe' : user.name
    }));
    setUsers(newUsers);
  }
  
  return(
    <div>
      <button onClick={() => edit1(2)}>Edit-1</button>
      <button onClick={() => edit2(5)}>Edit-2</button>
      <ul>
        {users.map((user) => (<li key={user.key}>{user.name}</li>))}
      </ul>
    </div>
  );
}

`

哪种方法更好?在edit1和edit2之间,哪种方法更好,因为它们都完成了任务?或者还有其他方法可以做到这一点?

问题是相当直接的。在edit1中,没有创建新对象,而是创建了一个新数组。因为rerender只检查对数组对象的引用是否已经更改,因此它会转到rerender。在edit2中,还创建了新的对象以及新的数组。这也会导致改进机。我搞不懂哪种方法更好。

EN

回答 2

Stack Overflow用户

发布于 2022-11-21 19:34:08

使用edit2,您可以在内部创建一个新数组和新元素。但是使用edit1,即使您有一个新的数组,内部的对象仍然对旧的对象有参考价值。所以我建议edit2。

票数 0
EN

Stack Overflow用户

发布于 2022-11-21 19:52:26

您应该使用"setState“的函数版本。这样就可以获取当前状态,这样您就可以不依赖于状态本身来设置它。如果你在useEffect里面有这个,你可以无限循环。

代码语言:javascript
运行
复制
setUsers((existingUsers) =>
  existingUsers.map((user) => ({
    ...user,
    name: user.id === id ? "John Doe" : user.name // Apply change within spread
  }))
);

如果您想避免扩散;因为这可能会对深嵌套结构产生问题,您可以使用一个不可变的库,比如Immer。此外,Immer是由Redux使用。

代码语言:javascript
运行
复制
setUsers(
  produce((draftUsers) => {
    draftUsers.forEach((user) => {
      if (user.id === id) {
        user.name = "Jane Doe"; // Directly mutate the draft state
      }
    });
  })
);

Immer还有一个useImmer钩子,您可以使用它来改变状态。这样就不需要将produce调用放在状态更新的中间。

有关更多信息,请参见:https://github.com/immerjs/use-immer

代码语言:javascript
运行
复制
const [users, updateUsers] = useImmer([]); // use-immer hook

const edit3 = (id) => {
  updateUsers((draftUsers) => {
    draftUsers.forEach((user) => {
      if (user.id === id) {
        user.name = "Jane Doe";
      }
    });
  });
};

工作实例

有关活动版本,请参见CodeSandbox

代码语言:javascript
运行
复制
import { useEffect, useState } from "react";
import produce from "immer";

const App = () => {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    (async () => {
      const response = await fetch(
        "https://jsonplaceholder.typicode.com/users"
      );
      const users = await response.json();
      setUsers(users);
    })();
  }, []);

  // Spread existing
  const edit1 = (id) => {
    setUsers((existingUsers) =>
      existingUsers.map((user) => ({
        ...user,
        name: user.id === id ? "John Doe" : user.name
      }))
    );
  };

  // Using Immer
  const edit2 = (id) => {
    setUsers(
      produce((draftUsers) => {
        draftUsers.forEach((user) => {
          if (user.id === id) {
            user.name = "Jane Doe";
          }
        });
      })
    );
  };

  return (
    <div>
      <button onClick={() => edit1(2)}>Edit-1</button>
      <button onClick={() => edit2(5)}>Edit-2</button>
      <ul>
        {users.map((user) => (
          <li key={user.key}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default App;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74523910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档