Estou tentando extrair dados do Open Data para montar um rápido mapa de calor. No processo, quero adicionar algumas estatísticas. Quase tudo corre bem porque tenho os dados e sou capaz de renderizar o mapa, mas não tenho certeza de como lidar com os cálculos depois de obter os dados, pois leva tempo para os dados chegarem. Como faço para configurar as coisas para que Posso executar uma função em uma variável de estado se ainda não tiver recebido dados necessariamente? Atualmente, estou recebendo um nulo como o número que é passado como adereços ao StatCard.
Abaixo estão minhas tentativas:
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;
Tentativa de reparo
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();
}
javascript
reactjs
fetch
react-props
LoF10
fonte
fonte
this.setState({ data: res, loading: true})
um erro de digitação narequestData
função? não develoading
ser definido comofalse
quando os dados são buscados?Respostas:
Renderize somente
<StatCard />
se você tiver os dados necessários:fonte
await requestData()
vez de adicioná-lo diretamente à função requestData, e adicionarasync fetchData = () => {}
. Melhor ainda,fetchData
só deve buscar os dados e armazená-los no estado. Então você deve usarcomponentDidUpdate
para dispararcalculateInspections()
apenas quandothis.state.data
mudançasPrimeiro de tudo , não acho que você precise de uma função separada
calculateInspections()
. Você pode colocar essa lógica nothen
retorno de chamada.Em segundo lugar , a configuração
this.state.totalInspections
é efetivamente redundante, pois você pode:Por fim, evite usar o
componentDidUpdate()
gancho quando for novo para reagir. Na maioria das vezes você acaba atirando no próprio pé.Atualmente, seu reparo por tentativa acabou de colocar você em um loop infinito de renderização. Isso acontece porque sempre que você chama
setState()
, ele chamacomponentDidUpdate()
o gancho do ciclo de vida após a renderização. Mas dentro decomponentDidUpdate()
você ligar novamentesetState()
, o que induz uma chamada de acompanhamento para o mesmo gancho de ciclo de vida e, portanto, o loop continua.Se você deve usar
componentDidUpdate()
e ligar parasetState()
dentro, regra geral, sempre coloque uma condição de parada à frente. No seu caso, será:fonte
Portanto, seu problema é que o estado isLoading precisa ser definido SINCRONIZAMENTE antes de qualquer chamada assíncrona.
Então, no seu componentDidMount:
Isso garante o carregamento assim que você faz a ligação. Em seguida, sua ligação é feita e essa parte é ASSÍNCRONA. Assim que os dados chegam, o carregamento é concluído
Além disso: seu método de renderização pode ter várias instruções de retorno Em vez de ter jsx condicional, retorne seu layout de carregamento
fonte
Aqui está a minha solução.
fonte