2016-09-13 3 views
10

Создание небольшого приложения для реагирования, которое передает геолокацию (определяется браузером дочернему компоненту в качестве реквизита).реагировать this.props undefined или empty object

Первый компонент: 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> 
    ); 
    } 
} 

Этот компонент определяет местоположение, сохраняет широту и долготу состояния и передает эту информацию через реквизит к компоненту Weather.jsx, который работает, как вы можете см на рисунке ниже:

enter image description here

и в weather.jsx компоненте я пытаюсь получить доступ к этим реквизита и получить либо неопределенное или пустой объект.

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)}&#176;</span> 
       <h2 className="description">{this.state.weather.description}</h2> 
      </div> 
     </div> 
    ) 
    } 
} 

На самом деле не уверен, что проблема заключается в качестве реагирующих инструментов Дев показывает, что компонент погоды действительно имеет место, установленное в реквизите, которые передаются вниз к этому компоненту.

Edit ** Решено:

Так что вопрос в том, что состояние устанавливается асинхронно, и что мой компонент погода была оказана, прежде чем состояние было обновлено.

Простая проверка значений внутри состояния во время метода рендеринга решила проблему.

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> 
    ); 
    } 
+1

Что делать, если вы переводите логику инициализации в 'componentDidMount' вместо' componentWillMount'. Возможно, реквизит не дошел до компонента, так как элемент еще не установлен в DOM. После монтажа, затем выполните работу. https://facebook.github.io/react/docs/component-specs.html – lux

+0

Спасибо за предложение, к сожалению, это не повлияло. Однако я только что понял, что если я просто верну реквизит в функции рендеринга, он работает, и я вижу реквизиты render4ed на странице. Так что до сих пор не знаю, почему функция 'startApp()' не может получить к ним доступ. – chinds

ответ

9

Я считаю, что проблема заключается в следующем. SetState происходит асинхронно. Из-за этого ваша функция рендеринга срабатывает до того, как реквизиты широты и долготы имеют данные. Если у вас будет какая-то проверка перед рендерингом компонента Weather, у вас, вероятно, не будет этой проблемы. Вот пример того, что я имею в виду.

render() { 
    let myComponent; 
    if(check if props has val) { 
     myComponent = <MyComponent /> 
    } else { 
     myComponent = null 
    } 
    return (
     <div> 
      {myComponent} 
     </div> 
    ) 
} 
+0

красивой и простой, это работает. не могу поверить, что я не думал об этом раньше !. Спасибо. – chinds

+1

да это может быть настоящей готкой! –

2

Вы должны связать startApp() и getWeather() к компоненту, в противном случае 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); 
    } 
    ... 
} 
+0

Хорошо, так что имеет смысл. С этим изменением я могу теперь получить доступ к реквизитам. однако реквизиты широты и долготы почему-то возвращаются как пустые строки, даже сейчас инструменты реагирования проявляют фактическое значение в реквизитах. Итак, если я 'console.log (this.props)' в 'componentWillMount' включен в конструкторе, я получаю:' Object {latitude: "", longitude: ""} ' – chinds

+1

Вы должны привязать' startApp() ' и getLocation() 'в вашем компоненте' App'. – QoP

+0

Просто сделайте это и все равно получите ту же пустую строку – chinds

 Смежные вопросы

  • Нет связанных вопросов^_^