[英]ReactJs re-render on state change
我正在尝试执行以下操作以获取一些API数据并按如下方式进行操作:
我在正确安排所有这些异步活动的时间方面遇到了一些麻烦(对于Javascript我是很陌生的)。
这是我到目前为止的内容:
class Map extends Component {
constructor(props) {
super(props);
this.state = {
addresses = [],
geocodedAddresses = []
}
}
componentDidMount() {
const geocodedAddresses = []
fetch('.....')
.then(result => result.json())
.then(addresses => this.setState({ addresses }, function() {
this.state.addresses.forEach(address => {
Geocode.fromAddress(address).then(geocodedAddress => {
geocodedAddresses.push(geocodedAddress['results'][0]['geometry']['location'])
})
})
}))
console.log(geocodedAddresses) //Correctly contains the geocoded addresses
this.setState({ geocodedAddresses })
}
}
render() {
this.state.addresses.map(a => console.log(a)) //Evaluates correctly
this.state.geocodedAddresses.map(ga => console.log(ga)) //Yields nothing....
.....
}
}
所以我不太明白为什么我这样做时React不会重新渲染this.setState({ geocodedAddresses })
-当我执行setState时不应该重新渲染吗?
您的代码有几个错误。 首先,使用equals而不是冒号创建状态对象:
this.state = {
addresses: [],
geocodedAddresses: []
}
其次,您应考虑到代码是异步的。 只有当通过调用产生的诺言Geocode.fromAddress
解决您为您的数据geocodedAddresses
。
在componentDidMount
,您正在控制台记录geocodedAdresses
并报告看到了正确的值。 这仅是因为在承诺解决之后,日志已更新。 但是,当你做console.log
在那一刻的价值geocodedAdresses
是一个空数组。 这就是在组件state
插入的值。
为了为状态设置正确的值,您应该在所有Geocode.fromAddress
承诺均已解决后调用setState
。 为此,您可以使用Promise.all方法。
因此,您的代码如下所示:
class Map extends Component {
constructor(props) {
super(props);
this.state = {
addresses: [],
geocodedAddresses: []
}
}
componentDidMount() {
fetch('.....')
.then(result => result.json())
.then(addresses => {
Promise.all(addresses.map(address => Geocode.fromAddress(address)))
.then(geocodedAddresses => {
this.setState({
addresses,
geocodedAddresses
})
});
}))
}
}
render() {
this.state.addresses.map(a => console.log(a)) //Evaluates correctly
this.state.geocodedAddresses.map(ga => console.log(ga)) //Yields nothing....
.....
}
}
请注意,使用此解决方案, setState
仅被调用一次。
由于您所有的state
涉及到地址信息,因此有可能将该信息合并到state
的单个键中。 您可以在构造函数中将state
初始化为:
this.state = {
addresses: []
};
然后,一旦所有承诺都解决,您就可以填充state
:
componentDidMount() {
fetch('.....')
.then(result => result.json())
.then(addresses => {
Promise.all(addresses.map(address => Geocode.fromAddress(address)))
.then(geocodedAddresses => {
const addressesState = addresses.map((address, i) => {
return {
address,
geocodedAddress: geocodedAddresses[i]
};
});
this.setState({ addresses: addressesState })
});
}))
}
}
您说对了,这是异步稍微关闭了。 console.log
将在它“出现”在控制台中后填充,但是当setState
被调用时(以及console.log
被调用时),它的值仍然是[]
。
如果您使用的是async/await
,则可以等待fetch
链完全完成,或者将setState
放在then
。 使用setState
回调,最好执行后者。
componentDidMount() {
const geocodedAddresses = []
fetch('.....')
.then(result => result.json())
.then(addresses => this.setState({ addresses }, function() {
this.state.addresses.forEach(address => {
Geocode.fromAddress(address).then(geocodedAddress => {
geocodedAddresses.push(geocodedAddress['results'][0]['geometry']['location'])
})
})
console.log(geocodedAddresses) //Correctly contains the geocoded addresses
this.setState({ geocodedAddresses })
}))
}}
要么
componentDidMount = async () => {
const geocodedAddresses = []
let addresses = await fetch('.....').then(result => result.json())
addresses.forEach(address => { // assuming this is sync
Geocode.fromAddress(address).then(geocodedAddress => {
geocodedAddresses.push(geocodedAddress['results'][0]['geometry']['location'])
})
})
this.setState({ geocodedAddresses,addresses })
}}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.