reactjs - 尽管处于状态,但在 forEach 函数中进行 Axios 调用以修改对象在渲染中未被识别
问题描述
我正在尝试学习完整堆栈 React 应用程序的基础知识,但我的 API 调用遇到了一个非常奇怪的问题。
我想从作为对象数组返回的数据库中检索预告片列表。然后,我使用 promise 循环该数组,并对数组中的每个项目进行单独的 API 调用,以向对象添加键值对。在我构建了该对象数组后,我将其设置为我的应用程序状态,然后通过道具将其传递给子组件,该子组件应根据数组中的信息呈现元素列表。
现在,控制台记录组件接收的数组和所有数据,但是,除了在 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) 向我显示了一个完整的数组,其中包含一个对象数组,该键值存在 { vote: 1 } 但它什么也不渲染。怎么会这样?我已经把头撞到墙上两天了,但我承认我对 API 和 Promise 很陌生。我的印象是,承诺应该确保在继续下一步之前完成调用,并且我正确记录的状态似乎暗示代码的该方面按预期运行。
解决方案
console.log(props) 向我显示了一个完整的数组,其中包含一个对象数组,该键值存在 { vote: 1 } 但它什么也不渲染。怎么会这样?
定时。您启动循环,拨打电话,然后不要等到他们完成;你setState
会遇到未填充的预告片,然后一段时间后 axios 会开始填充它们。
需要了解的一件事console.log
(至少在 Chrome 中)是它在渲染对象时也是异步的。您记录的任何字符串都将按原样记录;但是对象需要时间来绘制,当浏览器开始使用它时,它可能会在绘制时绘制对象,而不是在记录时。所以你看到的不是setState
看到的。请参阅Chrome 的 JavaScript 控制台是否懒于评估数组?使用JSON.stringify
或挑选原始值来记录真实存在的内容。
您需要做的是确保then
循环之后出现在循环之后(即当所有结果都完成时)。要做到这一点,有两件事需要发生。
1)现在,axios
循环的每次迭代(及其then
链)中的承诺都被丢弃了——没有任何东西在等待它。如果我们返回它,并把它forEach
变成 a map
,我们会得到一个 promise 数组。
2) 要等待数组中的所有承诺,请使用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;
})
))
})
推荐阅读
- html - 即使在全屏角度下如何制作自定义视频控制器
- python - 计算 CSV 中有多少命名列 [python pandas]
- javascript - 单击“后退”按钮时,从幻灯片中的第一张图像立即移动到最后一张图像
- python - 如何增加流域中标记线的宽度/大小?
- python - 这行代码使程序对重启功能没有反应
- junit - 我正在编写 Mockito 测试用例,但我在这个测试用例中有一些问题
- sql - 如何使用触发功能将行的值从一列移动到另一列?
- c++ - 仅在父级上更改 QGroupBox 的标题颜色
- python - 属性错误:“列表”对象没有属性“地图”
- ios - `scanFloat` 在 iOS 13.0 中已弃用