项目中使用react-redux插件中的connect,来完成 所有组件与sotre的连接,并且会自动监听store里的state的变化
但是有时会出现一些问题,代码没有错误的情况下,状态更新了(访问state时里确定store里的state是更新了的,但是组件并未渲染)
拿万能todolist举例
const initialState = {
todos:[
{
"id":1,
"text":'aaaa',
"flag":false,
visible:true
},
{
"id":2,
"text":'ccc',
"flag":true,
visible:true
},
]
}
export default (state = initialState, action) => {
switch (action.type) {
case 'ADD':
var newState ={ ...state};//此处为浅拷贝
newState.todos.push({
id:Date.now(),
text:action.text,
flag:false,
visible:true
})
return newState;
case 'REMOVE':
var newState =JSON.parse(JSON.stringify(state)); //此处为深拷贝
var index = newState.todos.findIndex((item)=>item.id===action.id);
newState.todos.splice(index,1);
return newState;
default:
return state
}
}
以上是todolist案例中的添加和删除功能
输入123并回车添加

在todos数组中添加一项之后,组件并没有重新渲染,但是state里的todos数组已经增加了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2nKDm4GZ-1582637903347)(/Users/junyi.mac/Library/Application Support/typora-user-images/image-20200225204909023.png)]
可以看到todos已经增加了,但是页面并没有渲染(此处console是另一个组件打印的,特意用来测试,与展示todos的组件无关)
原因分析:
原因要从一个骚操作说起
connect有两种使用方式
//方式1
var mapState = (state)=>{
return {
list:state.todos.todos
}
}
export default connect(mapState,actionCreator)(List);
//方式2
export default connect((state)=>state)(List);
一般用第二种方式比较多
我把connect第一个参数改写了一下,用一个list代替state.todos.todos,这样就在props上加个一个list的属性,这样做的好处是可以直接从this.props解构出list,就不用结构出todos然后再用todos.todos的方式读取数组
这个属性是sotre里todos模块中的todos数组的引用
重点看方式1中这段代码
list:state.todos.todos
这里我偷了个懒,直接拿着todos.todos的引用传递,使得组件里监听不到todos数组的改变(监听不到可能是因为list和todos是引用传递,当todos变换时list也跟着变化,对比不到差异,所以监听器失效)
解决方式:
既然知道原因,解决起来也很简单了,针对这个案例有两种解决方式
//方式1
var mapState = (state)=>{
return {
list:[...state.todos.todos]
}
}
追加一层浅拷贝(也可以用深拷贝),让list拿到的不再是todos的引用,而是值传递
//方式2
export default (state = initialState, action) => {
switch (action.type) {
case 'ADD':
//浅拷贝改为深拷贝
//var newState ={ ...state};//此处为浅拷贝
var newState =JSON.parse(JSON.stringify(state)); //此处为深拷贝
newState.todos.push({
id:Date.now(),
text:action.text,
flag:false,
visible:true
})
return newState;
case 'REMOVE':
var newState =JSON.parse(JSON.stringify(state)); //此处为深拷贝
var index = newState.todos.findIndex((item)=>item.id===action.id);
newState.todos.splice(index,1);
return newState;
default:
return state
}
}
在reducer中,var newState ={ …state}浅拷贝改为深拷贝var newState =JSON.parse(JSON.stringify(state));
个人习惯第二种方式,可以封装成一个方法,给所有地方都用深拷贝,一劳永逸