在地图函数中react setState

IT技术 reactjs setstate
2021-05-23 23:30:57

我无法解决下面的问题。

该问题与异步 setState 维度有关。通常我使用回调,但在这里似乎不合适。

我的目标是创建一个状态(我将能够对其进行排序),该状态是通过迭代不同的状态而获得的,这些状态本身是在地图中创建的。

下面的函数调用我的不同方法,我们感兴趣的是最后两个。getUserPointssortArrayforUserRank

getPlayersByUser = () => {
database
  .ref(`pools/${this.state.selectedValue}`)
  .once("value")
  .then(data => {
    for (let item in data.val()) {
      this.setState({
        users: this.state.users.concat([item])
      });
      this.setState({ [item]: data.val()[item] });
    }
  })
  .then(this.makePlayersArray)
  .then(this.getUserPoints)
  .then(this.sortArrayforUserRank);


  getUserPoints = () => {
this.state.users.map(user => {
  // Create the dynamic name of the state, 1 for each user
  let userPoints = `${user}points`;

  // initializing the state for userPoint to be at 0 for future calculation
  this.setState({ [userPoints]: 0 });

  this.state[user].map(player => {
    database
      .ref(`players/${player}`)
      .child("points")
      .once("value")
      .then(data => {
        let points = parseInt(data.val());
        this.setState(state => ({
          [userPoints]: points + state[userPoints]
        }));
      });
  });
});

getUserPoints允许我动态创建state.userPoints总结从球员每个用户的所有点。

然后我期待sortArrayforUserRank下面使用更新的 state.userPoints 来创建我的最终 userArrayPoints 状态。

sortArrayforUserRank = () => {
this.state.users.map(user => {
  let userPoints = `${user}points`;
  this.setState(state => ({
    userArrayPoints: state.userArrayPoints.concat([
      { [user]: state[userPoints] }
    ])
  }));
});

目前, userArrayPoints 填充了 4 个对象,{[user]:0}而不是每个用户的最终点数总和。问题是sortArrayforUserRank在前一个 setState 完成之前被调用

我很想在其中使用 setState 回调,getUserPoints但是由于我在玩家地图函数中,它将为每个玩家调用它,而我想在用户 lvl 处理它以获得最终的点数总和。

我尝试使用componentDidUpdate, 并按照那些文章使 sur 使用 functionnal setState ,但无法弄清楚。

https://medium.com/@shopsifter/using-a-function-in-setstate-instead-of-an-object-1f5cfd6e55d1

https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b

您的帮助将不胜感激,

谢谢

3个回答

你不能做你在这里尝试的事情,setState因为它是异步的,并且会与该循环中每次迭代的不同状态发生冲突for ()

您可以做的是先提取状态,根据需要对其进行操作,然后运行setState(至少在下面的这个中)

.then(data => {
    // Pull out what you want to mess with here first
    const users = [ ...this.state.users ];
    const dataValObj = data.val();

    // Then use spread operator (or Object.assign/Array.concat)          
    this.setState({
      users: [ 
          ...users, 
          ...Object.keys(dataValObj)
      ],
      ...dataValObj
    });
})

似乎您在整个代码中都遵循了类似的模式。尝试将我在这里所做的应用于其他使用循环的区域setState

找到了一种使用以下Promise的方法来做到这一点。它允许我从循环中删除 setState 并直接对其进行处理,而不必依赖于 2 个 setstate。两个评论/答案都帮助我处理了这个问题,

  getUserPoints = () => {
this.state.users.map(user => {
  // Create the dynamic name of the state, 1 for each user
  let userPoints = `${user}points`;

  // initializing the state for userPoint to be at 0 for future calculation
  this.setState({ [userPoints]: 0 });

  let userCounter = 0;
  let promiseArrays = [];
  this.state[user].map(player => {
    let promise = database
      .ref(`players/${player}`)
      .child("points")
      .once("value")
      .then(data => {
        let points = parseInt(data.val());
        return (userCounter = userCounter + points);
      });
    promiseArrays.push(promise);
  });
  Promise.all(promiseArrays).then(() =>
    this.setState({
      userArrayPoints: this.state.userArrayPoints.concat({
        [user]: userCounter
      })
    })
  );
});

};

只需在 this.setState 中使用第二个参数。

第二个参数是一个将在设置状态后调用的函数。

this.setState({ name:value },() => {this.nameOfTheFunctionYouWantToRunNext() });