簡體   English   中英

無法在componentDidMount內設置狀態

[英]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 rowsthis.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM