[英]Cannot set state inside componentDidMount
我正在從Google地方搜索API中獲取一些數據,然后使用其地方ID來獲取特定地方的所有詳細信息。 位置搜索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;
請考慮我在代碼中添加的注釋以了解其行為。 請幫我解決一下這個。
提取是異步的,因此將在setState
執行后將結果推送到rows
,並且不會更新任何內容。 要獲得所需的行為,請刪除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
的一些(未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)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.