在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
的异步特性造成的。
让这两个停止相互竞争的简单有效方法是什么?
答案 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)
您的代码有一些问题:
Array.prototype.push(value.data)
返回新的长度,而不是新的数组。因此,this.setState({ counts: this.state.counts.push(value.data) });
正在将state.counts
变成一个数值this.state.counts.length + 1
,这可能是不希望的。console.log(this.state);
放入setState()
的回调参数中。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]
}));
});
});
}