Redux reducer对象payload访问:解决weather.data.map未定义报错
问题分析与解决方案
你的报错根源在于Reducer初始状态和后续返回的状态结构不匹配:一开始你把state初始化为空数组[],但后来改成返回包含data和meta的对象。组件初始化时,this.props.weather是数组,数组没有data属性,所以weather.data会是undefined,调用.map()自然会抛出"cannot read property map of undefined"错误。
下面提供两种解决方案,优先推荐第二种(更符合多城市数据的存储需求):
方案一:修正当前的对象结构状态
如果你想继续使用{ data: [], meta: '' }的对象结构,需要先统一初始状态的格式:
调整Reducer的初始状态
import { FETCH_WEATHER } from "../actions/index"; // 初始状态改为和后续返回一致的对象结构 export function WeatherReducer(state = { data: [], meta: '' }, action) { switch (action.type) { case FETCH_WEATHER: // 注意要展开state.data而不是state本身,保持结构一致性 return { data: [action.payload.data, ...state.data], meta: action.meta.city }; default: return state; } }这样组件初始化时,
this.props.weather.data是一个空数组,.map()可以安全调用。⚠️ 注意:这个方案里
meta只会存储最后一次搜索的城市名,如果你需要每个天气条目对应自己的城市名,这个结构不适用,推荐方案二。
方案二:让每个天气条目携带自己的城市名(更合理)
因为你需要每个城市的天气数据都关联对应的城市名称,更好的做法是把城市名合并到每个天气数据对象中,保持state为数组结构(符合Redux存储列表数据的习惯,也和你最初的可运行代码结构更接近):
修改Reducer
import { FETCH_WEATHER } from "../actions/index"; export function WeatherReducer(state = [], action) { switch (action.type) { case FETCH_WEATHER: // 将城市名和天气数据合并成一个对象,添加到数组开头 const cityWeather = { city: action.meta.city, ...action.payload.data }; return [cityWeather, ...state]; default: return state; } }调整组件代码
改回使用this.props.weather.map,并在renderWeather中直接访问城市名:renderWeather = cityData => { const conditions = cityData.forecast.simpleforecast.forecastday[0].conditions; const fHigh = cityData.forecast.simpleforecast.forecastday[0].high.fahrenheit; return ( <tr> <td>{cityData.city}</td> <td>{conditions}</td> <td>{fHigh}</td> </tr> ); }; render() { return ( <table className="table table-hover"> <thead> <tr> <th>City</th> <th>Conditions</th> <th>High (F)</th> <th>Humidity</th> </tr> </thead> <tbody>{this.props.weather.map(this.renderWeather)}</tbody> </table> ); }
这样修改后,每个天气条目都自带对应的城市名,不会出现覆盖问题,同时初始状态是空数组,.map()可以安全调用,完美解决你的错误。
内容的提问来源于stack exchange,提问作者Mike Holzbach
相关产品推荐
相关产品推荐

