在我的react / redux项目中,我有一个对数组进行排序的操作:
case 'SORT_BY_NAME':
var newList = state.list; //.slice()
newList.sort(function(a,b){
if (a.name > b.name){
return 1;
} else if (a.name < b.name){
return -1;
} else {
return 0;
}
});
return Object.assign({}, state, { list: newList } );
该操作根据所需的字段成功地对数组进行了排序,状态对象的形状符合我的预期,并且在我的反应组件mapStateToProps中被命中,并且在mapStateToProps中,状态值准确地反映了数组的排序状态 .
初始渲染很好 . 但是排序操作未能导致我的组件的渲染方法再次被调用,因此UI中的数据从未出现排序 .
我的项目的体系结构类似于Redux文档中的Reddit example . 但是,我也使用react-redux连接mapStateToProps . 以下是我的组件设计的精简版:
class MyComponent extends React.Component{
render(){
<ul>
{list.map(item =>
<li key={item.id}>
{item.name}
</li>
)}
</ul>
}
}
function mapStateToProps(state){
return {
list: state.list;
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent)
最终我意识到我的问题的简单解决方案是在使用slice()对其进行排序之前克隆列表 . 因此我的问题不是如何解决问题,而是为什么会出现这个问题 . 问题是redux的mapStateToProps没有调用render()吗?或者反应组件没有看到新的状态对象?
通过在mapStateToProps中设置断点,看起来好像正在设置/更改状态;根据Chrome调试器中的Redux devtools,该商店看起来应该如此 .
我的项目太大了,无法创建一个完全重现我的问题的演示小提琴 . 当我试图创建一个最小尺寸的小提琴来重现问题时,我更加困惑,因为当我不使用Redux的连接时不会发生这个问题 . Link to fiddle .
总而言之,我的问题是为什么使用mapStateToProps时排序没有生效 . 我最好的猜测是,如果我的排序操作改变了先前的状态,以便新状态与先前的状态匹配,那么就没有需要重新渲染的方差 . 也许mapStateToProps比较了先前状态和新状态,并且它没有将新道具与DOM中道具的表示进行比较 .
1 回答
React Redux
connect()
经过大量优化,并在假设mapStateToProps
是纯函数的情况下运行 .By calling state.list.sort() you are mutating the store state with is not allowed in Redux. 一般来说,最好记住哪些方法是变异的,哪些不是变异的 . 例如,
splice()
是突变但slice()
不是;push()
正在变异,但concat()
不是 . 你永远不应该使用从商店获得的状态的变异方法 .您还可以查看https://github.com/leoasis/redux-immutable-state-invariant之类的内容,以便更容易检测这些案例,或者使用https://facebook.github.io/immutable-js/或https://github.com/rtfeldman/seamless-immutable来强制实现不变性 . 这是可选的,取决于您 .