当父组件的状态更新时,React子组件不更新 [英] React Child component don't update when parent component's state update

查看:116
本文介绍了当父组件的状态更新时,React子组件不更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Google地方搜索API.当我从Google Place Search API获取一些数据时,它仅返回20条记录并给出下一页令牌以获取更多结果,然后我为每个位置获取Place_id,然后再次获取该位置的所有详细信息,因此我正在获取数据我所做的两次创建了两个组件,一个组件负责获取位置,这是我的父级组件,另一个负责使用place_id获取位置详细信息,这是我的子级组件.这是我的下面的代码

I'm working with Google place search API. When I fetch some Data from Google Place search API it only returns 20 records and gives a next page token for more results then I grab the Place_id for each place and then again I fetch all details of that place so I'm fetching data twice what I did is created two components, one is responsible for fetching places and it's my parent component and the other is responsible for fetching the place details using place_id and it's my child component. Here is my code below

1. Extractor.js(父组件)

1. Extractor.js (parent component)

import React, { Component } from 'react';
import Search from './Components/Search';
import Display from './Components/Display';
import Header from './Components/Header';
import Instructions from './Components/Instructions';

const URI = 'https://maps.googleapis.com/maps/api/place/textsearch/json?query=';
const placeURI = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
const API = '&key=xxxxxxxxxxxxxxxxxxxxxxxxx';
class Extractor extends Component {

    getData = (keyword, location, country) => {
        let dataURI = `${URI}${keyword}+${location}+${country}${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));
            let nextPageToken = jsonData.next_page_token;
            this.setState({nextPage: nextPageToken, googleData: jsonData, dataURI });

            //console.log(dataURI");
        })
        .catch((e)=> console.log(`Error! ${e.message}`));
    }

    isEmpty = (obj) => {
        for(var key in obj) {
            if(obj.hasOwnProperty(key))
                return false;
        }
        return true;
    }

  viewMore = () => {
    let dataURI = `${this.state.dataURI}&pagetoken=${this.state.nextPage}`;
        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));
            let nextPageToken = jsonData.next_page_token;
            this.setState({nextPage: nextPageToken, googleData: jsonData, dataURI });
            //console.log(dataURI");
        })
        .catch((e)=> console.log(`Error! ${e.message}`));
  }

    constructor(props){
        super(props);
        this.state = {
            googleData: [],
            nextPage: '',
      dataURI: ''
        }
    }

 render() {
     let displayData;
     if(this.state.googleData.status === 'OK'){
         displayData = <Display googleData={this.state.googleData} nextPageToken = {this.state.nextPage} api={API} placeURI = {placeURI} viewMore = {this.viewMore} />
     }
     else{
         displayData = <Instructions />
     }
   //console.log(this.state.dataURI);
    return (
      <div>
        <Header />
        <section>
          <Search getData={this.getData} />
                {displayData}
        </section>
      </div>
    );
  }
}

export default Extractor;

2. Display.js(子组件)

2. Display.js (Child component)

import React, { Component } from 'react';
import {
    Table,
    ProgressBar,
    Button
}
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;
        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(dataURI);
                this.setState(prevState => ({rows: [...prevState.rows, jsonData.result]}));
            })
            .catch((e) => console.log(`Error! ${e.message}`));
        }
    }

    viewMoreCall = () => {
      this.props.viewMore();
    }

    render() {
        //console.log(this.state.rows);
        return (
            <div>
                <ProgressBar now={45} />
                <Table striped bordered condensed hover responsive>
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Name</th>
                      <th>Full Address</th>
                      <th className="pno">Phone</th>
                      <th className="pno">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.index}</td>
                          <td>{listValue.name}</td>
                          <td>{listValue.formatted_address}</td>
                          <td>{listValue.formatted_phone_number}</td>
                          <td>{listValue.international_phone_number}</td>
                          <td><a href={listValue.website}>{listValue.website}</a></td>
                          <td>{listValue.rating}</td>
                        </tr>
                      );
                    })}
                  </tbody>
                </Table>
        <Button onClick={this.viewMoreCall} type="button">View More...</Button>
            </div>
        );
    }

}
export default Display;

当我单击在子组件中创建的查看更多"按钮时,将更改父组件的状态,但是这样做不会返回更多记录.

when I click view more button created in the child component I change the state of parent component, But doing this is not returning more records.

我想要实现的是,当用户单击查看更多按钮时,将更多数据添加到现有表中.

What I want to achieve is to append more data to my existing Table when user click view more button.

推荐答案

componentDidMount在初始安装期间仅被调用一次,因此您的this.state.rows之后不会得到更新.

componentDidMount is only called once during initial mounting, so your this.state.rows does not get updated afterwards.

添加componentDidUpdate以确保每当道具更改时都获取新数据:

Add in componentDidUpdate to make sure new data is fetched whenever props have changed:

componentDidMount() {
  this.setData();
}

componentDidUpdate(prevProps) {
  if (this.props !== prevProps) { // only fetch if props changed
    this.setData();
  }
}

setData() {
  const { records, API, placeURI } = this.props;
  const results = records.results.map((p_id) => {
    const dataURI = `${placeURI}${p_id.place_id}${API}`;
    const proxyUrl = 'https://cors-anywhere.herokuapp.com/';
    return fetch(proxyUrl + dataURI)
      .then(res => res.json())
      .then((data) => {
        const jsonData = JSON.parse(JSON.stringify(data));
        // console.log(dataURI);
        return jsonData.result;
      });
  });
  // I wait for all fetch results before updating the state
  // If you prefer to update the state for each row, you can use your original code  
  Promise.all(results)
    .then(res =>
      this.setState(prevState => ({
        rows: [...prevState.rows, ...res],
      })))
    .catch(e => console.log(`Error! ${e.message}`));
}

这篇关于当父组件的状态更新时,React子组件不更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆