使用react-redux插件,部分状态更新时,组件未渲染?可能是这个原因

​ 项目中使用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并回车添加

image-20200225202810815

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

个人习惯第二种方式,可以封装成一个方法,给所有地方都用深拷贝,一劳永逸

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值