【问题标题】:How to use React setState inside a loop?如何在循环中使用 React setState?
【发布时间】:2020-08-25 18:37:09
【问题描述】:

我有这个 createRoleMember 函数更新组件的状态,因此 React 可以在组件内重新渲染 table () 并将新添加的 roleMembers 显示为行。

  createRoleMember = (newRoleMember) => {
    this.setState((prevState) => {
      return { roleMembers: prevState.roleMembers.concat([newRoleMember]) };
    });
  };

当我添加一个成员时,代码有效,但如果数组包含多个值,createRoleMember 函数会使用正确数量的新行但使用相同的重复用户名重新呈现表(总是重复数组中的最后一个用户名)。

例如,如果数组看起来像这样 `["testOne, "testTwo", "testThree"],那么表格将像这样重新渲染:

testthree   xxx Aug 25, 2020    
testthree   xxx Aug 25, 2020    
testthree   xxx Aug 25, 2020

代替:

testtone    xxx Aug 25, 2020    
testttwo    xxx Aug 25, 2020    
testthree   xxx Aug 25, 2020

如果我重新加载页面,表格会显示正确的数据。

如何在循环中调用createRoleMember(其中包含setState)?

更多上下文

createRoleMember 函数在如下所示的循环中调用:

  aliasArray.forEach((currAlias) => {
    memberAttributes.alias = currAlias;
    const marshalledObj = AWS.DynamoDB.Converter.marshall(memberAttributes);

    const params = {
      TableName: "xxxx",
      Item: marshalledObj,
    };

    axios
      .post(
        "https://xxxxxx.execute-api.us-west-2.amazonaws.com/xxx/xxx",
        params
      )
      .then(() => {
        createRoleMember(memberAttributes);
        const newRow = document.getElementById(
          `${memberAttributes.alias}-${memberAttributes.Role}`
        );
        newRow.classList.add("new-row");
      });
  });
  • aliasArray: 一个字符串数组,如 "username1","username2"。

  • memberAttributes:包含成员数据的对象,例如,用户名、grantedBy、grantedOn。

  • newRow:允许我向用户提供反馈(以绿色突出显示新行)。

【问题讨论】:

    标签: javascript reactjs asynchronous setstate


    【解决方案1】:

    我认为问题出在您的代码中:

    aliasArray.forEach((currAlias) => {
        memberAttributes.alias = currAlias; // Here's the problem
    
        // ...
    
        axios
          .post(/*...*/)
          .then(() => {
            createRoleMember(memberAttributes);
            // ...
          });
      });
    

    每次调用 forEach 回调时,都会更新memberAttributes.alias 的值。所以aliasArray的所有成员都迭代完之后,memberAttributes.alias的值就是aliasArray的最后一个值。

    因此,当您的请求返回并执行成功回调 (.then(...)) 时,memberAttributes.alias 将是每次调用的最后一个 aliasArray 值。 我相信您的问题可以通过将currAlias 传播到成功回调来解决,例如:

    aliasArray.forEach((currAlias) => {
        memberAttributes.alias = currAlias;
        const marshalledObj = AWS.DynamoDB.Converter.marshall(memberAttributes);
    
        const params = {
          TableName: "xxxx",
          Item: marshalledObj,
        };
    
        axios
          .post(
            "https://xxxxxx.execute-api.us-west-2.amazonaws.com/xxx/xxx",
            params
          )
          .then(() => {
            memberAttributes.alias = currAlias;
            createRoleMember(memberAttributes); 
            const newRow = document.getElementById(
              `${currAlias}-${memberAttributes.Role}` // Modified this line
            );
            newRow.classList.add("new-row");
          });
      });
    
    
    createRoleMember = (newRoleMember) => {
        this.setState((prevState) => {
          return { roleMembers: prevState.roleMembers.concat([{...newRoleMember}]) };
        });
      };
    

    【讨论】:

    • 为什么我不能在then 之后立即执行memberAttributes.alias = currAlias?我试过但没有用,既然那不起作用,为什么createRoleMember(memberAttributes,currAlias) 会起作用?奇怪的原因,如果我console.log(currAlias) 我确实得到了两个日志,其中包含预期值。感谢您的帮助,不胜感激!
    • @TheDaniel 好点子,您应该可以在那时更新memberAttributes.alias,避免更改createRoleMember 的签名。我相信这里有一个微妙的错误。您正在更新 memberAttributes,然后(在 createRoleMember 中)将其推送到状态。但是你永远不会重新分配memberAttributes,所以状态中的每个对象实际上都是对同一个对象的引用。我已经更新了我的答案以包含此问题的修复程序。请注意,我现在使用 createRoleMember 中的对象扩展运算符来创建一个新对象。
    猜你喜欢
    • 2021-07-24
    • 2017-01-24
    • 2021-11-27
    • 2021-11-04
    • 1970-01-01
    • 2020-12-18
    • 2019-06-16
    • 2021-02-13
    • 1970-01-01
    相关资源
    最近更新 更多