尽管处于状态

时间:2019-07-10 04:57:40

标签: reactjs api axios

我正在尝试学习全栈React应用程序的基础知识,并且我的API调用遇到了一个非常奇怪的问题。

我想从数据库中检索作为对象数组返回的预告片列表。然后,我使用promise遍历该数组,并对数组中的每个项目进行单独的API调用,以将键值对添加到对象。构建完该对象数组后,将其设置为我的应用状态,然后将其通过prop传递到子组件,该子组件应根据数组中的信息呈现元素列表。

现在,控制台记录组件接收到的数组,并显示所有数据,但是,除了在forEach循环中添加的字段之外,每个字段都可以呈现。

我已经从forEach循环中删除了API调用,而只是在循环中设置了一个静态值,并且信息可以按预期正确地呈现。因此,我确定问题在于API调用处于循环中。我不知道为什么。日志显示数组已完成,因此渲染器找不到数据似乎没有意义。

// The API call

loadUserAndTrailers = () => {
        let trailers = []; 
        axios.get("http://localhost:5000/api/trailers")
        .then (res => {
            trailers = res.data;
        })
        .then (() => {          
            trailers.forEach(trailer => {

 axios.get(`http://localhost:5000/api/votes/user/${this.state.user.id}/${trailer.TrailerID}`)
                .then (res => {
                    const vote = res.data[0].Vote;
                    trailer.vote = vote;
                })
            })
        })
        .then (() => {
            this.setState({trailers: trailers});
        })
}

// The child component

const TrailerList = props => {

    console.log(props)

    const trailers = props.trailers.map(trailer => {
        return <div>{trailer.vote}</div>
    });

    return <div>{trailers}</div>;
};

// The return in the parent component

return (
  <div className="container">
    <div className="content">
      <h1>Trailers</h1>
      <div className="trailers">
      <TrailerList trailers={this.state.trailers}></TrailerList>
    </div>
  </div>
</div>
);

console.log(props)向我显示了一个完整的数组,其中包含一个对象数组,并且此键值存在{投票:1},但不呈现任何内容。怎么会这样?我已经将头撞墙了两天了,但是我对API和Promise还是陌生的。我的印象是,诺言应该确保在继续下一步之前调用已完成,而我正确记录的状态似乎暗示着代码的这一方面正在按预期运行。

1 个答案:

答案 0 :(得分:3)

  

console.log(props)向我显示了一个完整的数组,其中包含一个对象数组,并且此键值存在{投票:1},但不呈现任何内容。怎么会这样?

计时。您启动循环,进行调用,然后不要等待,直到它们完成;您的setState将遇到未填满的预告片,然后过一会儿axios将开始填充它们。

要了解console.log(至少在Chrome中是这样)的一点是,它在呈现对象时也是异步的。您记录的任何字符串都将原样记录;但是对象需要花费一些时间来绘制,并且当浏览器到达该对象时,它可能正在绘制该对象,就像在 drawing 时一样,而不是在 logging < / em>。因此,您所看到的不是setState所看到的。请参见Is Chrome's JavaScript console lazy about evaluating arrays?,使用JSON.stringify或选择原始值来记录实际值。

您需要做的是确保循环后的then在循环后的 之后(即所有结果完成后)。为此,有两件事需要发生。

1)现在,循环的每个迭代中的axios承诺(及其then链)都已被丢弃-没有任何等待。如果我们将其退回,并将forEach变成map,我们将获得一系列的承诺。

2)要等待数组中的所有promise,请使用Promise.all

所以...

.then (() =>
  Promise.all(trailers.map(trailer =>
    axios.get(`${baseUrl}/${this.state.user.id}/${trailer.TrailerID}`)
    .then(res => {
      const vote = res.data[0].Vote;
      trailer.vote = vote;
    })
  ))
})