【问题标题】:React setState in a map function在地图函数中反应 setState
【发布时间】:2017-12-10 03:31:52
【问题描述】:

我无法解决以下问题。

该问题与异步 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 完成之前被调用

我很想在getUserPoints 中使用 setState 回调,但由于我在玩家地图函数中,它将为每个玩家调用它,而我想在用户 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

您的帮助将不胜感激,

谢谢

【问题讨论】:

  • 让我理解你的getUserPoints,有多个用户,每个用户有多个玩家?您能否举例说明用户对象的外观?如果我是正确的,您最终希望 setState 为您的组件状态与用户及其总点数,您无需进行如此多的状态更新。
  • 嗨@NanduKalidindi 你说对了我的最终目标-根据每个用户各自的玩家获得总分 DB中的个人用户对象看起来像{userName : "playerName1, playerName2, playerName3..."}我将其设为个人状态对于每个看起来像 {userName: [playerName1, playerName2, playerName3 etc]} 的用户同时我的用户状态对象是一个数组 {users:[userName1, userName2 etc]} 我目前的想法是获得一个最终状态 userArrayPoints 看起来像 {[{userName1: totalUser1Points},{userName2: totalUser2Points}]}

标签: reactjs setstate


【解决方案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 的循环的区域。

【讨论】:

  • 谢谢@Deryck,但我很难弄清楚在这种情况下它如何帮助我,而且我肯定没有完全理解你的答案。我假设在创建this.state.users 之后,您的逻辑将在getUserPoints 中使用。在getUsersPoints 中,我迭代user,因为我使用它们的名称来访问数据库中的值。我尝试从循环中删除 setState ,但它总是在我解决承诺(来自数据库请求)之前调用 setState 。这就是为什么我在循环内的请求之后使用 setState
【解决方案2】:

找到了一种使用以下所有承诺的方法。它允许我从循环中删除 setState 并直接对其进行处理,而不必依赖 2 个 setstate。 cmets/answer 都帮助我处理了这个问题,

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

};

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 2018-11-03
      • 2023-03-20
      • 2016-12-23
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      相关资源
      最近更新 更多