Estoy intentando extraer datos de Open Data para armar un mapa de calor rápido. En el proceso quiero agregar algunas estadísticas. Casi todo funciona bien porque tengo los datos y soy capaz de representar el mapa, pero no estoy seguro de cómo manejar los cálculos una vez que obtengo los datos, ya que lleva tiempo ingresarlos. ¿Cómo configuro las cosas para que ¿Puedo ejecutar una función en una variable de estado si aún no ha recibido necesariamente los datos? Actualmente obtengo un valor nulo como el número que se pasa como accesorios a StatCard.
A continuación están mis intentos:
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;
Intento de reparación
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
fuente
fuente
this.setState({ data: res, loading: true})
un error tipográfico en larequestData
función? noloading
debería establecerse enfalse
cuando se obtienen los datos?Respuestas:
Solo renderice
<StatCard />
si tiene los datos que necesita:fuente
await requestData()
lugar de agregarlo directamente a la función requestData y agregarasync fetchData = () => {}
. Mejor aún,fetchData
solo debe buscar los datos y almacenarlos en estado. Entonces debería usarcomponentDidUpdate
para dispararcalculateInspections()
solo cuando losthis.state.data
cambiosEn primer lugar , no creo que necesites una función separada
calculateInspections()
. Puede poner esa lógica en lathen
devolución de llamada.En segundo lugar , la configuración
this.state.totalInspections
es efectivamente redundante, ya que puede hacer:Por último, evite usar el
componentDidUpdate()
gancho cuando sea nuevo en reaccionar. La mayoría de las veces terminas disparándote en el pie.Actualmente, su intento de reparación acaba de meterlo en un bucle de renderizado infinito. Esto sucede porque cada vez que llama
setState()
, llamará acomponentDidUpdate()
gancho de ciclo de vida después de la representación. Pero dentro decomponentDidUpdate()
usted vuelve a llamarsetState()
, lo que induce una llamada de seguimiento al mismo enlace de ciclo de vida, y por lo tanto, el ciclo continúa.Si debe usar
componentDidUpdate()
y llamar alsetState()
interior, regla general, siempre coloque una condición de detención por delante. En tu caso, será:fuente
Entonces, su problema es que el estado de carga debe establecerse SINCRÓNICAMENTE antes de cualquier llamada asíncrona.
Entonces, en su componenteDidMount:
Esto garantiza la carga tan pronto como realice la llamada. Luego se realiza su llamada y esa parte es ASINCRÓNICA. Tan pronto como los datos lleguen, la carga estará lista.
Más aún: su método de representación puede tener múltiples declaraciones de retorno En lugar de tener jsx condicional, devuelva su diseño de carga
fuente
Aquí está mi solución.
fuente