在反应中初始化状态时无法读取未定义的 属性
cannot read property of undefined when initialize state in react
我正在尝试使用 React 和 Flux 制作一个预测应用程序。我从 Yahoo Weather API 获取数据,并通过视图中的 jsonp request.Then 回调将数据放入我的商店,我从商店获取数据(在 componentDidMount()
中)作为状态并将它的一些属性传递给 child 组件。
数据(this.state.store
),是一个Object,有两个属性,叫做condition
和forecast
。问题是如果我想通过this.state.store.condition
(或forecast
)到child,它说TypeError: Cannot read property 'condition' of undefined
。但是如果我只是尝试访问this.state.store
(例如console.log(this.state.store)
),就没有错误。
此外,如果我尝试在 try-catch
语句中访问 this.state.store.condition,并在出现错误时记录错误,我确实成功访问了条件,控制台打印了 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);
},
};
工具:
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'));
在我看来,您试图在从远程 API.
获取 this.state.store[this.state.currentCity]
属性 之前访问它
您可以添加某种指示,表明仍在像这样获取数据。
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() 方法并再次调用 render()。第二次它将通过 if 和 运行 您的代码。
我正在尝试使用 React 和 Flux 制作一个预测应用程序。我从 Yahoo Weather API 获取数据,并通过视图中的 jsonp request.Then 回调将数据放入我的商店,我从商店获取数据(在 componentDidMount()
中)作为状态并将它的一些属性传递给 child 组件。
数据(this.state.store
),是一个Object,有两个属性,叫做condition
和forecast
。问题是如果我想通过this.state.store.condition
(或forecast
)到child,它说TypeError: Cannot read property 'condition' of undefined
。但是如果我只是尝试访问this.state.store
(例如console.log(this.state.store)
),就没有错误。
此外,如果我尝试在 try-catch
语句中访问 this.state.store.condition,并在出现错误时记录错误,我确实成功访问了条件,控制台打印了 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);
},
};
工具:
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'));
在我看来,您试图在从远程 API.
获取this.state.store[this.state.currentCity]
属性 之前访问它
您可以添加某种指示,表明仍在像这样获取数据。
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() 方法并再次调用 render()。第二次它将通过 if 和 运行 您的代码。