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

时间:2016-05-07 08:43:38

标签: javascript reactjs flux

我正在尝试使用React和Flux制作预测应用。我从Yahoo Weather API获取数据,并使用jsonp请求中的回调将数据放入我的商店。然后在View中,我从商店获取数据(在componentDidMount()中)作为状态并传递一些属性它是儿童组件。

作为对象的数据(this.state.store)有两个属性,名为conditionforecast。问题是如果我想传递this.state.store.condition (或forecast)给孩子,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);
    },
};

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'));

1 个答案:

答案 0 :(得分:0)

在我看来,您试图在从远程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并运行你的代码。