Construire une petite application de réaction qui passe la géolocalisation (déterminée par le navigateur à un composant enfant en tant qu'accessoire).
Le premier composant: App.jsx
import React, {Component} from 'react';
import DateTime from './components/dateTime/_dateTime.jsx';
import Weather from './components/weather/_weather.jsx';
import Welcome from './components/welcome/_welcome.jsx';
require ('../sass/index.scss');
export default class App extends Component {
constructor() {
super();
this.state = {
latitude: '',
longitude: ''
};
this.showPosition = this.showPosition.bind(this);
}
startApp () {
this.getLocation();
}
getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(this.showPosition);
} else {
console.log("Geolocation is not supported by this browser.");
}
}
showPosition(position) {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude
})
}
componentWillMount () {
this.startApp();
}
render() {
return (
<div className="container">
<div className="header-container">
<Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />
<DateTime />
</div>
<div className="welcome-container">
<Welcome name="Name" />
</div>
</div>
);
}
}
Ce composant détermine l'emplacement, enregistre la latitude et la longitude dans l'état et transmet ces informations via des accessoires au composant Weather.jsx, qui fonctionne comme vous pouvez le voir dans l'image ci-dessous:
Et dans le composant weather.jsx, j'essaie d'accéder à ces accessoires et d'obtenir un objet non défini ou vide.
import React, {Component} from 'react';
import Fetch from 'react-fetch';
export default class Weather extends Component {
constructor(props) {
super(props);
this.state = {
forecast: {},
main: {},
weather: {},
};
this.setWeather = this.setWeather.bind(this);
}
getWeather (latitude, longitude) {
var self = this;
fetch('http://api.openweathermap.org/data/2.5/weather?lat=' + latitude + '&lon=' + longitude + '&units=metric&APPID=ed066f80b6580c11d8d0b2fb71691a2c')
.then (function (response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + response.status);
return;
}
response.json().then(function(data) {
self.setWeather(data);
});
})
.catch (function (err) {
console.log('Fetch Error :-S', err);
});
}
setWeather (forecast) {
var main = forecast.main;
var weather = forecast.weather[0];
this.setState({
main: main,
weather: weather,
forecast: forecast
});
}
startApp () {
this.getWeather(this.props.latitude, this.props.longitude);
}
componentWillMount () {
this.startApp();
}
componentDidMount () {
// window.setInterval(function () {
// this.getWeather();
// }.bind(this), 1000);
}
render() {
return (
<div className="">
<div className="weather-data">
<span className="temp">{Math.round(this.state.main.temp)}°</span>
<h2 className="description">{this.state.weather.description}</h2>
</div>
</div>
)
}
}
Je ne sais vraiment pas quel est le problème, car les outils de développement de rea montrent que le composant météo a bien l'emplacement défini dans les accessoires qui lui sont transmis.
Modifier ** résolu:
Le problème était donc que l'état est défini de manière asynchrone et que mon composant météo a été rendu avant la mise à jour de l'état.
Une simple vérification des valeurs dans l'état pendant la méthode de rendu a résolu le problème.
render() {
if (this.state.latitude != '' && this.state.longitude != '') {
var weatherComponent = <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />
} else {
var weatherComponent = null;
}
return (
<div className="container">
<div className="header-container">
{weatherComponent}
<DateTime />
</div>
<div className="welcome-container">
<Welcome name="Name" />
</div>
</div>
);
}
Je crois que le problème est le suivant. SetState se produit de manière asynchrone. De ce fait, votre fonction de rendu est activée avant que les accessoires de latitude et de longitude aient des données. Si vous en aviez quelques-uns à vérifier avant de rendre votre composant Weather, vous n'auriez probablement pas ce problème. Voici un exemple de ce que je veux dire.
render() {
let myComponent;
if(check if props has val) {
myComponent = <MyComponent />
} else {
myComponent = null
}
return (
<div>
{myComponent}
</div>
)
}
Vous devez lier startApp()
et getWeather()
au composant, sinon this
serait undefined
.
export default class Weather extends Component {
constructor(props) {
super(props);
this.state = {
forecast: {},
main: {},
weather: {},
};
this.setWeather = this.setWeather.bind(this);
this.getWeather = this.getWeather.bind(this);
this.startApp = this.startApp.bind(this);
}
...
}
Vous devez garder le rendu autant que propre. Évitez de faire si sinon dans rend faire si sinon vérifie en retour avec l'opérateur ternaire ou l'opérateur && Effectuez une vérification conditionnelle comme ci-dessous et appelez ensuite MyComponent comme ci-dessous
render() {
return (
<div>
{this.state.latitude != '' && this.state.longitude != '' ? <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />: null}
{this.state.latitude != '' && this.state.longitude != '' && <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />}
</div>
)
}