在map函数中反应setState

时间:2017-12-10 03:31:52

标签: reactjs setstate

我无法解决下面的问题。

该问题与异步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},而不是每个用户的最终点数总和。问题是在前一个setState完成之前调用了sortArrayforUserRank

我本来喜欢在getUserPoints中使用setState回调,但由于我在玩家地图功能中会为每个玩家调用它,而我想在用户lvl处理它以获得最终的积分总和。

我尝试使用componentDidUpdate,并根据这些文章使用函数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 个答案:

答案 0 :(得分:1)

您无法使用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的循环的其他区域。

答案 1 :(得分:0)

使用下面的承诺找到了一种方法。它允许我从循环中删除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
      })
    })
  );
});

};

答案 2 :(得分:0)

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

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

this.setState({           名称:值         },()=> {this.nameOfTheFunctionYouWantToRunNext()});