简体   繁体   中英

How to use React setState inside a loop?

I have this createRoleMember function that updates a component's state so React can re-render table () inside the component and display the newly added roleMembers as rows.

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

The code works when I add a single member, but if the array contains more than one value, the createRoleMember function re-renders the table with the correct amount of new rows but with the same repeated username (always duplicating the last username in the array).

For example, if the array looks like this `["testOne, "testTwo", "testThree"], the table will be re-rendered like this:

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

Instead of:

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

If I reload the page, the table displays the correct data.

How can I call createRoleMember (which contains setState ) inside a loop?

More Context

The createRoleMember function gets called in a loop that looks like this:

  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 : an array of strings like "username1","username2".

  • memberAttributes : an object with the member's data, eg, username, grantedBy, grantedOn.

  • newRow : allows me to provide feedback to the user (highlights new row in green).

I believe the issue is in your code here:

aliasArray.forEach((currAlias) => {
    memberAttributes.alias = currAlias; // Here's the problem

    // ...

    axios
      .post(/*...*/)
      .then(() => {
        createRoleMember(memberAttributes);
        // ...
      });
  });

Each time the forEach callback is invoked, you're updating the value of memberAttributes.alias . So after all the members of aliasArray have been iterated, the value of memberAttributes.alias is the last value of aliasArray .

So when your requests come back and the success callback ( .then(...) ) is executed, memberAttributes.alias is going to be that last value of aliasArray for each invocation. I believe your issue would be resolved by propagating currAlias through to the success callback like:

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}]) };
    });
  };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM