Javascript 无法在componentDidMount内设置状态
我从Google place search API中获取一些数据,然后使用其位置ID获取特定位置的所有详细信息。place search API返回一个包含20条记录的数组,首先,我循环一个数组,获取每个位置的place_id,然后再次获取循环中位置的详细信息,并将其放入数组中,然后将状态设置为该数组。但是当我在render函数中执行Javascript 无法在componentDidMount内设置状态,javascript,reactjs,google-maps-api-3,fetch,Javascript,Reactjs,Google Maps Api 3,Fetch,我从Google place search API中获取一些数据,然后使用其位置ID获取特定位置的所有详细信息。place search API返回一个包含20条记录的数组,首先,我循环一个数组,获取每个位置的place_id,然后再次获取循环中位置的详细信息,并将其放入数组中,然后将状态设置为该数组。但是当我在render函数中执行{this.state.rows}时,它会给我一个空数组。 下面是我的代码: import React, { Component } from 'react'; i
{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;
import React,{Component}来自'React';
进口{
桌子
进度条
}
来自“反应引导”;
类显示扩展了组件{
建造师(道具){
超级(道具);
这个州={
行:[]
}
}
componentDidMount(){
var records=this.props.googleData;
const API=this.props.API;
const placeURI=this.props.placeURI;
var行=[];
for(让p_id记录。结果){
让dataURI=`${placeURI}${p_id.place_id}${API}`;
让proxyUrl为https://cors-anywhere.herokuapp.com/',
targetUrl=dataURI
获取(代理URL+目标URL)
.然后((res)=>res.json())
。然后((数据)=>{
让jsonData=JSON.parse(JSON.stringify(data));
//console.log(jsonData);
rows.push(jsonData.result);
})
.catch((e)=>console.log(`Error!${e.message}`));
}
这是我的国家({
行:行
});
};
render(){
console.log(this.state.rows);//此行在控制台上打印两个数组,一个为空,另一个为值填充。
返回(
#
名称
全称
电话号码
国际邮政编码
网站
评级
{this.state.rows.map((listValue,index)=>{
返回(
{listValue.name}
{listValue.formatted_address}
{listValue.name}
{listValue.name}
{listValue.name}
{listValue.name}
{listValue.name}
);
})}
{this.state.rows+“hell”}//此行没有返回我的当前状态
);
}
}
导出默认显示;
请考虑我在代码中添加的注释以了解行为。请帮我解决这个问题。Fetch是异步的,因此在执行
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}`));
}
它无法工作,因为获取是异步的。(例如:行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)
}
Async/await for循环非常优雅,但在这里它们消除了并行性,因为每次获取都需要服务器响应,然后才能发送下一个。你说得对。这样做只保留一个设置状态。我们可以说我使代码工作,但不是最优化的。你的答案很理想,但我又犯了一个错误this.loadArray不是componentDidMount
内部的函数,请详细说明。我是React的初学者。没有得到你的答案。这远远超出了我的水平,非常感谢。我真的很感谢你。我真的很感激。我在这件事上浪费了两天时间。再次非常感谢你