如何正确地反应时间数据渲染?

时间:2019-11-15 20:27:56

标签: javascript reactjs fetch react-props

我正在尝试从“开放数据”中提取数据,以建立快速的热图。在此过程中,我想添加一些统计信息。几乎所有东西都运行良好,因为我有数据并能够渲染地图,但是我不确定一旦获得数据就如何处理计算,因为数据需要花费一些时间才能进入。如何设置数据以便如果尚未接收到数据,我可以在状态变量上运行一个函数吗?目前,我收到的是作为作为道具传递给StatCard的数字。

以下是我的尝试:

App.js

  import React, { Component } from 'react';
import Leaf from './Leaf';
import Dates from './Dates';
import StatCard from './StatCard';
import classes from './app.module.css';

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      data:[],
      cleanData:[],
      dateInput: '2019-10-01',
      loading: false,
      totalInspections: null,
      calculate: false
    };
  }

  componentDidMount() {
    try {
      this.fetchData();
    } catch (err) {
      console.log(err);
      this.setState({
        loading: false
      })
    }
  }


  fetchData=()=>{
    const requestData = async () => {
      await fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${this.state.dateInput}'&$limit=50000`)
        .then(res => res.json())
        .then(res =>
          //console.log(res)
          this.setState({ data: res, loading: true})
        )
    }

    const  calculateInspections = () => {
      this.setState({totalInspections: this.state.data.length})
    }

    //call the function
    requestData();

    if(this.state.data) {
      calculateInspections();
    }
  }

  handleDateInput = (e) => {
    console.log(e.target.value);
    this.setState({dateInput:e.target.value, loading: false}) //update state with the new date value
    this.updateData();
    //this.processGraph(e.target.value)
  }

  updateData =() => {
    this.fetchData();
  }

  LoadingMessage=()=> {
    return (
      <div className={classes.splash_screen}>
        <div className={classes.loader}></div>
      </div>
    );
  }


  //inspection_date >= '${this.state.dateInput}'& 
 // https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=inspection_date >= '2019-10-10T12:00:00' 

  render() {



    return (
      <div>

        <div>{!this.state.loading ? 
              this.LoadingMessage() : 
              <div></div>}
        </div>

        {this.state.totalInspections && <StatCard totalInspections={this.state.totalInspections} /> }

          <Dates handleDateInput={this.handleDateInput}/>
          <Leaf data={this.state.data} />

      </div>
    );
  }
}

export default App;

StatCard.js

import React from 'react';


const StatCard = ( props ) => {

    return (
        <div >
            { `Total Inspections: ${props.totalInspections}`}
        </div>
    )
};

export default StatCard;

尝试修复

   componentDidMount() {
    try {
      this.fetchData();
    } catch (err) {
      console.log(err);
      this.setState({
        loading: false
      })
    }
  }


  componentDidUpdate () {
    if(this.state.data) {
      this.setState({totalInspections: this.state.data.length})
    }
  }

  fetchData= async ()=>{
    const requestData = () => {
    fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${this.state.dateInput}'&$limit=50000`)
        .then(res => res.json())
        .then(res =>
          //console.log(res)
          this.setState({ data: res, loading: true})
        )
    }
    //call the function
    await requestData();

  }

4 个答案:

答案 0 :(得分:0)

仅在拥有所需数据时才渲染<StatCard />

{this.state.totalInspections && <StatCard totalInspections={this.state.totalInspections} /> }

答案 1 :(得分:0)

首先,我认为您不需要单独的功能calculateInspections()。您可以将该逻辑放入then回调中。

fetchData = () => {
  fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${this.state.dateInput}'&$limit=50000`)
    .then(res => res.json())
    .then(data => {
      this.setState({
        data: data,
        loading: true,
        totalInspections: this.state.data.length
      })
    })
}

其次,设置this.state.totalInspections实际上是多余的,因为您可以执行以下操作:

{this.state.data && <StatCard totalInspections={this.state.data.length} /> }

最后,避免对新手有反应时使用componentDidUpdate()钩子。大多数时候,您最终会用脚射击自己。

当前,您的Attempt Repair仅使您陷入无限渲染循环。发生这种情况的原因是,每当您调用setState()时,它将在渲染后调用componentDidUpdate()生命周期挂钩。但是在componentDidUpdate()中,您再次调用 setState(),这会引起对同一生命周期挂钩的后续调用,因此循环不断进行。

如果必须凭经验使用componentDidUpdate()并在内部调用setState(),请务必在其前面放置一个停止条件。在您的情况下,它将是:

componentDidUpdate () {
  if (this.state.data) {
    if (this.state.totalInspections !== this.state.data.length) {
      this.setState({ totalInspections: this.state.data.length })
    }
  }
}

答案 2 :(得分:0)

所以您的问题是,在进行任何异步调用之前,需要同步设置isLoading状态。

因此在您的componentDidMount中:

componentDidMount() {
    try {
      this.setState({ loading: true }); // YOU NEED TO SET TRUE HERE
      this.fetchData();
    } catch (err) {
      console.log(err);
      this.setState({
        loading: false
      })
    }
}

这样可以确保在您拨打电话后立即加载。 然后,您拨打了电话,那部分是异步的。 数据一经加载即完成

.then(data => {
  this.setState({
    data: data,
    loading: false, // THIS NEEDS TO BE FALSE
    totalInspections: this.state.data.length
  })
})

更多: 您的render方法可以有多个return语句 返回条件加载列表,而不是使用条件jsx

render() {

    if (this.state.loading) {
        return <div> I am loading </div>
    }

    return <div> Proper Content </div>;

}

答案 3 :(得分:0)

这是我的解决方法。

class App extends Component {

    constructor(props) {
        super(props);
        this.state = {
            data: [],
            dateInput: '2019-10-01',
            loading: false,
            error: false
        };
    }

    async componentDidMount() {
        try {
            await this.fetchData(this.state.dateInput);
        } catch (err) {
            this.setState({ loading: false, error: true });
        }
    }

    fetchData = (date) => new Promise(resolve => {
        this.setState({ loading: true });
        fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${date}'&$limit=50000`)
            .then(res => res.json())
            .then(res => {
                this.setState({ data: res, loading: false, error: false });
                resolve(res.data);
            });
    })

    handleDateInput = e => {
        this.setState({ dateInput: e.target.value }) //update state with the new date value
        this.fetchData(e.target.value);
    }

    render() {
        const { loading, data } = this.state;
        return (
            <div>
                {loading && (
                    <div className={classes.splash_screen}>
                        <div className={classes.loader}></div>
                    </div>
                )}
                {data && <StatCard totalInspections={data.length} />}
                <Dates handleDateInput={this.handleDateInput} />
                <Leaf data={data} />
            </div>
        );
    }
}