Erstellen einer kleinen Reaktions-App, die die Geolocation (vom Browser an eine untergeordnete Komponente als Requisiten übergeben) übergibt.
Die erste Komponente: 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>
);
}
}
Diese Komponente bestimmt den Standort, speichert die geografischen Breiten- und Längengrade und gibt diese Informationen über Requisiten an die Komponente Weather.jsx weiter, die wie in der folgenden Abbildung dargestellt funktioniert:
Und in der weather.jsx-Komponente versuche ich, auf diese Requisiten zuzugreifen und bekomme entweder ein undefiniertes oder ein leeres Objekt.
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>
)
}
}
Wirklich nicht sicher, was das Problem ist, da die reaktiven Entwicklungswerkzeuge zeigen, dass die Wetterkomponente tatsächlich die Position in den Requisiten aufweist, die an diese Komponente weitergegeben werden.
Bearbeiten ** Gelöst:
Das Problem war also, dass der Status asynchron gesetzt wurde und dass meine Wetterkomponente gerendert wurde, bevor der Status aktualisiert wurde.
Eine einfache Überprüfung der Werte innerhalb des Zustands während der Rendermethode löste das Problem.
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>
);
}
Ich glaube, das Problem ist wie folgt. SetState geschieht asynchron. Aus diesem Grund wird Ihre Renderfunktion ausgelöst, bevor die Längen- und Breitengradeigenschaften Daten haben. Wenn Sie vor dem Rendern Ihrer Weather-Komponente eine Prüfung hätten, hätten Sie wahrscheinlich dieses Problem nicht. Hier ist ein Beispiel von dem, was ich meine.
render() {
let myComponent;
if(check if props has val) {
myComponent = <MyComponent />
} else {
myComponent = null
}
return (
<div>
{myComponent}
</div>
)
}
Sie müssen startApp()
und getWeather()
an die Komponente binden, andernfalls wäre this
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);
}
...
}
Sie müssen so viel wie sauber rendern. Vermeiden Sie if if else in render stattdessen, wenn else direkt mit dem ternären Operator oder dem Operator && prüft. Führen Sie die bedingte Überprüfung wie unten beschrieben aus und rufen Sie dann MyComponent wie unten beschrieben auf
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>
)
}