简体   繁体   English

反应componentDidMount()初始化状态

[英]React componentDidMount() initializing state

Working on a small project in React, and I'm using Axios to grab information from an API that is tested working. 在React的一个小项目上工作,我正在使用Axios从经过测试工作的API中获取信息。 The problem is when I pull in the data and try to update the component state, the values coming in from the API aren't getting filled into the state to be rendered in the component. 问题是当我提取数据并尝试更新组件状态时,来自API的值没有被填充到要在组件中呈现的状态中。

I've been trying to get the data in the state like so: 我一直在尝试使数据处于这种状态:

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

a previous version was written like so: 以前的版本是这样写的:

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

Both situations end up with the same result. 两种情况最终都有相同的结果。 The state is never really updated with the new count array. 状态永远不会真正用新的count数组更新。 I have the suspicion that this is due to the async nature of Axios and setState . 我怀疑这是由于Axios setState的异步特性引起的。

What would be a simple, effective way to get these two to stop racing each other? 一种简单有效的方法来使这两个人停止比赛?

In the first version you are correct that it is due to the async nature of the service. 在第一个版本中,您正确地认为这是由于服务的异步性质所致。 You are logging the output, but this is happening before the service has resolved. 您正在记录输出,但这是在服务解决之前发生的。

In the second (previous) example you are setting the state before it resolves. 在第二个(上一个)示例中,您要在状态解析之前进行设置。 I would recommend the following approach, creating an array of the promises then waiting for all of them to resolve before you update state: 我建议采用以下方法,创建一个promise数组,然后在更新状态之前等待所有promise解析:

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

Don't use console.log immediately after setting the state since it is asynchronous. 设置状态后不要立即使用console.log ,因为它是异步的。 Do it with a callback to setState . 通过对setState的回调来实现。

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

or inspect your state in your render method with console.log 或使用console.log在渲染方法中检查状态

Also, rather than doing it forEach , try to make all the request in one time with Promise.all if this suits you. 另外,不要对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]
        }))
      })
  }

A few problems with your code: 您的代码有一些问题:

  1. Array.prototype.push(value.data) returns the new length, not the new array. Array.prototype.push(value.data)返回新的长度,而不是新的数组。 So this.setState({ counts: this.state.counts.push(value.data) }); 因此this.setState({ counts: this.state.counts.push(value.data) }); is making state.counts into a number value this.state.counts.length + 1 , which is probably not desired. 正在将state.counts转换为数字值this.state.counts.length + 1 ,这可能是不希望的。
  2. If you want to print out the new state, the console.log(this.state); 如果要打印新状态,请使用console.log(this.state); should be put into the callback param of setState() . 应该放在setState()的回调参数中。
  3. Your previous version did not await for the axios call before setState . 您的先前版本未在setState之前等待axios调用。 You got the idea right. 您的想法正确。

The issues was I was attempting to mutate state. 问题是我试图改变状态。 (I've been horrible with immutable data.... so something I'll have to get used to.) (我一直对不可变数据感到恐惧...。因此我必须习惯一些东西。)

My solution code is as follows: 我的解决方案代码如下:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM