2016-05-07 2 views
1

Я пытаюсь создать приложение прогноза с помощью React and Flux. Я беру данные из Yahoo Weather API и помещаю данные в свой магазин с обратным вызовом в запросе jsonp. Затем в представлении я получаю данные (в componentDidMount()) из хранилища как состояние и передаю некоторые свойства его дочерним компонентам ,не может прочитать свойство undefined при инициализации состояния в реакции

Данные (this.state.store), который представляет собой объект, обладает двумя свойствами, называется condition и forecast .The проблема заключается в том, что если я хочу передать this.state.store.condition (или forecast) ребенка, это говорит TypeError: Cannot read property 'condition' of undefined. Но если я просто попытаюсь получить доступ к this.state.store (например, console.log(this.state.store)), ошибок нет.

Кроме того, если я попытаюсь получить доступ к this.state.store.condition в операторе try-catch и зарегистрировать сообщение об ошибке при его наличии, я успешно получаю доступ к этому состоянию с указанной выше консолью TypeError.

Вот мои коды:

магазин:

const CHANGE_EVENT = 'change'; 
let _app = {}; 
// create a city 
function create(city, data) { 
    _app[city.toUpperCase()] = { 
     condition: data.condition, 
     forecast: data.forecast, 
    }; 
} 
const AppStore = Object.assign({}, EventEmitter.prototype, { 
    getAll() { 
     return _app; 
    }, 
    emitChange() { 
     this.emit(CHANGE_EVENT); 
    }, 
    addChangeListener(callback) { 
     this.on(CHANGE_EVENT, callback); 
    }, 
    removeChangeListener(callback) { 
     this.removeListener(CHANGE_EVENT, callback); 
    }, 
}); 
// register callback 
AppDispatcher.register((action) => { 
    switch (action.actionType) { 
     case AppConstants.CREATE_CITY: { 
      create(action.city, action.data); 
      AppStore.emitChange(); 
      break; 
     } 
     // other cases 

     default: 
      // noop 
    } 
}); 

действия:

function callback(city, data) { 
    console.log(data); 
    const action = { 
     actionType: AppConstants.CREATE_CITY, 
     city, 
     data, 
    }; 
    AppDispatcher.dispatch(action); 
} 

const AppActions = { 
    create(city) { 
     getDataFromAPI(city, callback); 
    }, 
}; 

Utils: просмотров

function getDataFromAPI(query, callback) { 
    let data; 
    const url = `https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where u='c' AND woeid in (select woeid from geo.places(1) where text="${query}")&format=json`; 
    superagent 
     .get(url) 
     .use(jsonp) 
     .end((err, res) => { 
      console.log(res.body.query.results.channel.item); 
      data = res.body.query.results.channel.item; 
      callback(query, data); 
     }); 
} 

:

class App extends React.Component { 
    constructor(props) { 
     super(props); 
     this.state = { 
      store: Store.getAll(), 
      currentCity: 'BEIJING', 
     }; 
     this.onChange = this.onChange.bind(this); 
     this.getCurrentCity = this.getCurrentCity.bind(this); 
    } 
    componentWillMount() { 
     AppActions.create('BEIJING'); 
    } 
    componentDidMount() { 
     Store.addChangeListener(this.onChange); 
    } 
    onChange() { 
     this.setState({ store: Store.getAll() }); 
    } 
    getCurrentCity(city) { 
     this.setState({ currentCity: city.toUpperCase() }); 
    } 
    componentWillUnmout() { 
     Store.removeChangeListener(this.onChange); 
    } 
    render() { 
     // For now, I have to do all of these to pass the condition to the child component 
     let condition; 
     let forecast; 
     let text; 
     let temp; 
     let currentWeatherCode; 
     let forecastWeatherCode = []; 
     let currentWeatherClassName; 
     let forecastWeatherClassName = []; 
     let date; 
     let forecastDate = []; 
     console.log(this.state.store[this.state.currentCity]);<--NO ERROR 

     // console.log(this.state.store[this.state.currentCity])<--UNDEFINED 
     // console.log(this.state.store[this.state.currentCity].condition);<--CANNOT READ PROPERTY 
       ^
       | 
       ERROR ON THIS 2 STATEMENTS   

     try { 
      condition = this.state.store[this.state.currentCity].condition; 
      forecast = this.state.store[this.state.currentCity].forecast; 
      text = condition.text.toUpperCase(); 
      temp = condition.temp; 
      currentWeatherCode = condition.code; 
      currentWeatherClassName = setWeatherIcon(currentWeatherCode); 
      date = condition.date; 
      for (let i = 0; i < 6; i++) { 
       forecastWeatherCode.push(forecast[i].code); 
       forecastWeatherClassName.push(setWeatherIcon(forecastWeatherCode[i])); 
       forecastDate.push(forecast[i].date); 
      } 
     } catch (err) { 
      console.log(err);<--STILL ERROR, BUT I DO ACCESS THE PROP CONDITION IN THIS WAY 
     } 
     return (
      <div> 
       <Today 
        city={this.state.currentCity} 
        weatherStatus={text} 
        tempreture={temp} 
        currentWeatherClassName={currentWeatherClassName} 
        date={date} 
       /> 
      </div> 
     ); 
    } 
} 

ReactDOM.render(<App />, document.querySelector('#app')); 

ответ

0

Мне кажется, что вы пытаетесь получить доступ к свойству this.state.store[this.state.currentCity] до того, как оно будет извлечено из удаленного API.

Вы можете добавить какое-то указание на то, что данные все еще извлекаются так.

render() { 
     // For now, I have to do all of these to pass the condition to the child component 
     let condition; 
     let forecast; 
     let text; 
     let temp; 
     let currentWeatherCode; 
     let forecastWeatherCode = []; 
     let currentWeatherClassName; 
     let forecastWeatherClassName = []; 
     let date; 
     let forecastDate = []; 
     console.log(this.state.store[this.state.currentCity]);<--NO ERROR 

     if (!this.state.store.hasOwnProperty(this.state.currentCity)) { 
       return <div>Loading...</div>; 
     } 

     ... the rest of your original code 
} 

После завершения загрузки вызывается метод setState() и вызывается(). Во второй раз он упадет через код if и запустит ваш код.

+0

Спасибо. Оно работает. Но я все еще смущен. Если я могу успешно зарегистрировать 'this.state.store [this.state.currentCity]', это должно означать, что состояние больше не пусто. Итак, почему я не могу одновременно записывать 'this.state.store [this.state.currentCity]' и 'this.state.store [this.state.currentCity] .condition'? Если я это сделаю, 'this.state.store [this.state.currentCity] 'даже станет неопределенным. – Downpooooour

+0

Доступ к неопределенному свойству в JS не является ошибкой. Попытка получить доступ к свойству неопределенного свойства приводит к ошибке. Таким образом, вы также можете написать if, если так: 'if (! This.state.store [this.state.currentCity]) {', и он все равно будет работать. – Christiaan

+0

Итак, вы имеете в виду, что я могу только log 'this.state.store [this.state.currentCity]' успешно, потому что в то время система уже извлекла данные. Но если я запишу и «this.state.store [this.state.currentCity]» и «this.state.store [this.state.currentCity] .condition', в то время они не существовали? Это звучит странно. – Downpooooour

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