组件挂载时无法加载Mock数据,Redux状态与组件显示不一致
问题分析与修复方案
你遇到的问题主要来自两个关键错误:Reducer中错误地将数组状态转为对象,以及组件中列表计算的时机不对,导致组件无法正确获取Redux中的数据。
1. Reducer的状态类型错误
你的loadCoctails reducer初始状态是一个空数组[],但在处理LOAD_COCTAILS动作时,你用了对象展开语法:
return { ...state, ...INIT_COCTAILS }
这会把原本的数组状态强制转换成对象——数组展开到对象中时,会把数组的索引作为对象的键,比如[a,b,c]会变成{0:a,1:b,2:c}。而组件中你用数组的map方法去遍历这个对象,自然不会得到任何结果,因为map是数组的专属方法,对象没有这个方法。
修复Reducer
如果你想直接用mock数据替换初始空数组,直接返回INIT_COCTAILS即可;如果是要追加数据,就用数组展开语法:
export const loadCoctails = (state = [], { type }) => { switch(type) { case LOAD_COCTAILS: // 替换初始空数组为mock数据 return INIT_COCTAILS; // 如果是追加数据,用下面这行: // return [...state, ...INIT_COCTAILS]; default: return state; } }
2. 组件中列表计算的时机错误
你把list定义成了类的实例属性:
list = this.props.loadCoctails.map(...)
这个属性只会在组件实例化的时候计算一次,此时this.props.loadCoctails还是初始的空数组。之后Redux更新了状态,组件的props也会更新,但这个实例属性不会重新计算,所以渲染的还是最初的空列表。
修复组件
把列表的计算逻辑移到render方法内部(或者用类的getter方法),这样每次组件渲染时,都会使用最新的props数据:
class ResultsCoctails extends Component { componentDidMount() { this.props.actionLoadCoctails(); } render() { // 每次render时都基于最新的props生成列表 const list = this.props.loadCoctails.map(({ img, name, tags }, index) => { const showDetail = (e) => { e.preventDefault(); this.props.actionToggleDetail(); }; return ( <div className="item" key={`coctail-${index}`}> <a href="#" onClick={showDetail}> <div className="img"> <img src={img} alt="Cocktail" /> </div> <div className="desc"> <div className="name">{name}</div> <TagsBlock tags={tags} /> </div> </a> </div> ); }); return ( <div className="result-coctails"> <div className="block">{list}</div> <ActionButton txt="more"></ActionButton> </div> ); } }
另外补充一个小细节:最好避免用数组索引作为key(如果你的数据有唯一ID的话优先用ID),不过暂时用索引也能解决当前问题。
总结
修复这两个问题后,组件就能正确获取Redux中的mock数据并渲染列表了:
- Reducer保证状态始终是数组类型,支持
map遍历 - 列表计算逻辑跟随组件渲染周期,每次都拿到最新的props数据
内容的提问来源于stack exchange,提问作者markdeitchell
相关产品推荐
相关产品推荐

