反应componentDidMount()初始化状态

时间:2018-07-27 15:38:45

标签: javascript arrays reactjs setstate

在React的一个小项目上工作,我正在使用Axios从经过测试工作的API中获取信息。问题是当我提取数据并尝试更新组件状态时,从API传入的值没有被填充到要在组件中呈现的状态中。

我一直在尝试使数据处于这样的状态:

  componentDidMount() {
    this.state.databases.forEach(d => {
      axios.get(`http://localhost:3204/customer/${d}/count`).then(value => {
        this.setState({ counts: this.state.counts.push(value.data) });
      });
    });
    console.log(this.state);
  }

以前的版本是这样写的:

componentDidMount() {
    let internalCounts = [];
    this.state.databases.forEach(d => {
        axios.get(`http://localhost:3204/customer/${d}/count`).then(value => {
            internalCounts.push(value.data);
        });
    });
    this.setState({count: internalCounts});
}

两种情况最终都得到相同的结果。状态永远不会真正用新的count数组更新。我怀疑这是由于Axios setState的异步特性造成的。

让这两个停止相互竞争的简单有效方法是什么?

4 个答案:

答案 0 :(得分:2)

在第一个版本中,您正确地认为这是由于服务的异步性质所致。您正在记录输出,但这是在服务解析之前发生的。

在第二个(上一个)示例中,您要在状态解析之前进行设置。我建议采用以下方法,创建一个诺言数组,然后在更新状态之前等待它们全部解决:

componentDidMount() {
    const promises = [];
    this.state.databases.forEach(d => {
        promises.push(axios.get(`http://localhost:3204/customer/${d}/count`));
    });
    Promise.all(promises).then(results => {
        const internalCounts = [];
        results.map(result => {
            internalCounts.push(result.data);
        });
        this.setState({count: internalCounts});
    })
}

答案 1 :(得分:1)

设置状态后不要立即使用console.log,因为它是异步的。通过回调setState来实现。

this.setState({...}, () => console.log(...))

或使用console.log

在渲染方法中检查状态

如果不适合,请尝试使用forEach一次提出所有请求,而不是Promise.all

componentDidMount() {
    const promiseArray = this.state.databases.map( d =>
      axios.get(`http://localhost:3204/${d}/count`)
    )
    Promise.all( promiseArray )
      .then( ( results ) => {
        const data = results.map( result => result.data);
        this.setState( prevState => ({
          counts: [ ...prevState.counts, ...data]
        }))
      })
  }

答案 2 :(得分:0)

您的代码有一些问题:

  1. Array.prototype.push(value.data)返回新的长度,而不是新的数组。因此,this.setState({ counts: this.state.counts.push(value.data) });正在将state.counts变成一个数值this.state.counts.length + 1,这可能是不希望的。
  2. 如果要打印出新状态,则应将console.log(this.state);放入setState()的回调参数中。
  3. 您的先前版本未在setState之前等待axios调用。您的想法正确。

答案 3 :(得分:0)

问题是我试图改变状态。 (我一直对不可变的数据感到恐惧...。所以我必须习惯一些东西。)

我的解决方案代码如下:

componentDidMount(){
    this.state.databases.forEach(d => {
        axios.get(`http://localhost:3204/${d}/count`).then(value => {
            this.setState(prevState => ({
                counts: [...prevState.counts, value.data]
            }));
         });
    });
}