Реагировать на оператор if в асинхронном вопросе l oop - PullRequest
0 голосов
/ 08 мая 2020

Помогите, я не могу понять, как решить эту проблему:

array.map(object => {
   console.log(this.state.newArr) // [] didn't update despite setState
   if (this.state.newArr.length === 0) {
      axios.get('http://localhost/')
      .then(res => {
         this.setState(prevState => ({ newArr: [...prevState.newArr, res] })) // setState here
      })
   }
})

Изменить: обновленный код реализовал ответы, но все еще не работает атм.

Ответы [ 2 ]

1 голос
/ 08 мая 2020

Шаблон async / await может быть решением. Никогда не пробовал использовать это на карте, но это будет примерно так:

array.map(async object => {
  if (this.state.newArr.length === 0) {
     const response = await axios.get('http://localhost/');
     await this.setStateAsync({ newArr: [...this.state.newArr, response] });
     // or without the setStateAsync 
     // this.setState(prevState => ({ newArr: [...prevState.newArr, response] })); 
  }
});

const setStateAsync = state => {
  return new Promise((resolve) => {
    this.setState(state, resolve)
  });
}
0 голосов
/ 08 мая 2020

setState равно asyn c, что означает, что при установке состояния в al oop у вас еще не будет обновленных значений состояния. Когда вы делаете обновления состояния на основе предыдущих значений состояния, вы должны использовать форму средства обновления setState.

Пример того, что идет не так

class Example extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: []
    }
  }
  
  componentDidMount() {
    [1,2,3].forEach((i) => {
      // setState is async, 
      // so it has not updated by the next loop
      // meaning its the same every cycle
      console.log(this.state.arr)
      this.setState({ arr: [...this.state.arr, i] });
    })
  }
  
  render() {
    // Only the last enty is in the array
    console.log('final', this.state.arr)
    return (<div>test</div>);
  }
}

ReactDOM.render(<Example/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Пример правильного пути

class Example extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: []
    }
  }
  
  componentDidMount() {
    [1,2,3].forEach((i) => {
      // Use the updater form so you are guaranteed
      // to have the most recent copy of state each update
      this.setState((prevState) => ({ arr: [...prevState.arr, i] }));
    })
  }
  
  render() {
   console.log('final: ', this.state.arr)
    return (<div>test</div>);
  }
}

ReactDOM.render(<Example/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Еще одна функция setState, которая может пригодиться здесь, - это вариант обратного вызова. Вы можете передать второй аргумент setState, который является функцией. Эта функция будет вызываться после обновления состояния, поэтому вы можете добавить туда logi c в зависимости от этих обновленных значений.

class Example extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: []
    }
  }
  
  componentDidMount() {
    [1,2,3].forEach((i) => {
      this.setState((prevState) => ({ arr: [...prevState.arr, i] }), () => {
        console.log('updated: ', this.state);
      });
      console.log('not updated: ', this.state);
    })
  }
  
  render() {
    return (<div>test</div>);
  }
}

ReactDOM.render(<Example/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
...