我从Google地方搜索API获取一些数据,然后使用其地点ID获取特定地点的所有详细信息。 place search API返回一个包含20条记录的数组,首先我遍历一个数组,然后获取每个地方的place_id,然后我再次获取循环内部位置的详细信息并将其推入数组,然后将状态设置为该数组。但是当我在渲染函数中执行{this.state.rows}
时,它会给我一个空数组。
这是我的代码下面:
import React, { Component } from 'react';
import {
Table,
ProgressBar
}
from 'react-bootstrap';
class Display extends Component {
constructor(props) {
super(props);
this.state={
rows: []
}
}
componentDidMount(){
var records = this.props.googleData;
const API = this.props.api;
const placeURI = this.props.placeURI;
var rows = [];
for (let p_id of records.results) {
let dataURI = `${placeURI}${p_id.place_id}${API}`;
let proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = dataURI
fetch(proxyUrl + targetUrl)
.then((res) => res.json())
.then((data) => {
let jsonData = JSON.parse(JSON.stringify(data));
//console.log(jsonData);
rows.push(jsonData.result);
})
.catch((e) => console.log(`Error! ${e.message}`));
}
this.setState({
rows:rows
});
};
render() {
console.log(this.state.rows); //this line is printing two arrays on console one is empty and the other is populated with values.
return (
<div>
<ProgressBar now={45} />
<Table striped bordered condensed hover responsive>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Full Address</th>
<th>Phone Number</th>
<th>International P.no</th>
<th>Website</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
{this.state.rows.map(( listValue, index ) => {
return (
<tr key={index}>
<td>{listValue.name}</td>
<td>{listValue.formatted_address}</td>
<td>{listValue.name}</td>
<td>{listValue.name}</td>
<td>{listValue.name}</td>
<td>{listValue.name}</td>
<td>{listValue.name}</td>
</tr>
);
})}
</tbody>
</Table>
{this.state.rows+"hell"} // this line is not returning my current state
</div>
);
}
}
export default Display;
请考虑我在代码中添加的评论以了解行为。请帮帮我。
答案 0 :(得分:3)
Fetch是异步的,因此在rows
执行后,结果将被推送到setState
,并且不会更新任何内容。要获得所需的行为,请删除var rows
和this.setState({rows:rows})
,并将rows.push(jsonData.result)
替换为this.setState(prevState => ({rows: [...prevState.rows, jsonData.result]}))
。
请记住,行的顺序将取决于获取请求的完成顺序,因此,如果您想保证订单,则应创建fetch
承诺列表,并使用Promise.all
设置状态。您也可以使用async / await for循环,但这意味着每次提取都将等到上一次提取完成,从而消除并行性并损害性能。
更新:简而言之,请将componentDidMount
替换为:
componentDidMount(){
var records = this.props.googleData;
const API = this.props.api;
const placeURI = this.props.placeURI;
for (let p_id of records.results) {
const dataURI = `${placeURI}${p_id.place_id}${API}`;
const proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = dataURI
fetch(proxyUrl + targetUrl)
.then((res) => res.json())
.then((data) => {
const jsonData = JSON.parse(JSON.stringify(data));
//console.log(jsonData);
this.setState(prevState => ({rows: [...prevState.rows, jsonData.result]}))
})
.catch((e) => console.log(`Error! ${e.message}`));
}
};
更新2:这是一些带有Promise.all
的(未经测试的)代码,它保留了行顺序:
componentDidMount(){
const records = this.props.googleData;
const API = this.props.api;
const placeURI = this.props.placeURI;
const proxyUrl = 'https://cors-anywhere.herokuapp.com/'; // move this outside of component
const rowFetches = records.results.map((p_id) =>
fetch(`${proxyUrl}${placeURI}${p_id.place_id}${API}`)
.then((res) => res.json())
);
const rows = Promise.all(rowFetches)
.then((rows) => this.setState({rows}))
.catch((e) => console.log(`Error! ${e.message}`));
}
答案 1 :(得分:2)
它不起作用,因为fetch是异步的。 (例如:行rows.push(jsonData.result);
实际发生在this.setState({rows: rows});
之后!)
我建议您创建一个新函数,只是为了创建数组并将其设置为状态。为了更好的可读性,您可以使用async / await语法,这是我如何做的:
async loadArray(results){
const API = this.props.api;
const placeURI = this.props.placeURI;
let rows = [];
for (let p_id of results) {
let dataURI = `${placeURI}${p_id.place_id}${API}`;
let proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = dataURI
let res = await fetch(proxyUrl + targetUrl);
res = await res.json();
let jsonData = JSON.parse(JSON.stringfy(res))
rows.push(jsonData.result)
}
this.setState({
rows:rows
});
}
componentDidMount(){
const records = this.props.googleData;
this.loadArray(records.results)
}