在反应中初始化状态时无法读取未定义的 属性

cannot read property of undefined when initialize state in react

我正在尝试使用 React 和 Flux 制作一个预测应用程序。我从 Yahoo Weather API 获取数据,并通过视图中的 jsonp request.Then 回调将数据放入我的商店,我从商店获取数据(在 componentDidMount() 中)作为状态并将它的一些属性传递给 child 组件。

数据(this.state.store),是一个Object,有两个属性,叫做conditionforecast。问题是如果我想通过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 和 运行 您的代码。