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