react redux-immutable
Immutable.js
immutable出现的背景
在我们的日常开发中,我相信大家都遇到过一种困扰,那就是如何将后端返回的数据,深拷贝一份,再供我们自己使用呢?
如果用过React
框架开发过项目的小伙伴,也一定记得Redux
中的reducer
是基于纯函数设计的,要求返回的状态数据(对象或数组),需要先深拷贝一份(目的是:防止影响老状态),再根据自己的开发需求对其拷贝后的值操作?
这是使用redux、reducer中修改数据的代码:
let list = [{ name: 'house', age: 18}
]let newList = [...list];
newList[0].name = "dalukuankuan";console.log(list[0].name); // "dalukuankuan"
显然上面例子中的原数组list
,被我们不轻易间串改了,其实原因很简单,就是因为ES6中的展开运算符[...list]
是一个浅拷贝,浅拷贝的意思就是只复制对象或数组的第一级内容。
在上面中,可以发现经过展开运算符的浅拷贝,只复制了其内层引用类型的地址,当通过索引找到其引用地址,并改变它的时候,改的就是list
原数组本身。
当然,有的小伙伴可以想到:当访问到对象的属性值的时候,将属性值再进行递归对比,这样就达到了深层对比的效果,但是想想一种极端的情况,就是在属性有一万条的时候,只有最后一个属性发生了变化,那我们就不得已将一万条属性都遍历。这是非常浪费性能的。
回到问题的本质,无论是直接用浅层比对,还是进行深层比对,我们最终想知道的就是原对象里的属性有无改变。
在这样的条件下,immutable 数据应运而生。
什么是immutable数据?
「immutable」数据一种利用结构共享
形成的持久化数据结构
,一旦有部分被修改,那么将会返回一个全新的对象,并且原来相同的节点会直接共享。
每次修改一个 immutable 对象时都会创建一个新的不可变的对象,在新对象上操作并 不会影响到原对象的数据。
具体点来说,「immutable」 对象数据内部采用是多叉树的结构,凡是有节点被改变,那么它和与它相关的所有上级节点
都更新
。
用一张动图来模拟一下这个过程:
是吧!只更新了父节点
,比直接比对所有的属性简直强太多,并且更新后返回了一个全新的引用
,即使是浅比对也能感知到数据的改变。
因此,采用 「immutable」 既能够最大效率地更新数据结构,又能够和现有的 React中的 「PureComponent (memo)」 顺利对接,感知到状态的变化,是提高 React 渲染性能的极佳方案
。
不过,immutable 也有一些被开发者吐槽的点,首先是 immutable 对象
和 JS 对象
要注意转换,不能混用,这个大家注意适当的时候调用 toJS
或者 fromJS
即可,问题并不大。
immutable优化性能的方式
immutable
实现的原理是:持久化数据结构
,也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免deepCopy
把所有节点都复制一遍带来的性能损耗
。
immutable
使用了结构共享
,即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
与React中的 「PureComponent(memo)」 相结合,我们知道PureComponent
能够在内部帮我们比较新props
跟旧props
,新state
和旧state
,如果值相等
或者对象含有的相同的属性、且属性值相等
,便确定shouldComponentUpdate
返回true或者false,从而判断是否再次渲染render
函数。
看上述代码,我们可以看出来,当代码中使用immutable
第三库的时候,可以精确地深拷贝
a 对象,改a对象
中的select
属性赋值给b
之后,并不会影响原对象a
,而b
的select
属性变味了新值。
如果上述select
属性给一个组件用,因为其值被改变了,导致shouldComponentUpdate
应该返回true,而filter
属性给另一个组件用,通过判断,并无变化,导致shouldComponentUpdate
应该返回false,故此组件就避免了重复的diff算法对比
,大大提高了React中的性能优化。
这么好用的第三方库,我们来看一下它的基本用法:
immutable中常用类型
(1)Map() 包裹对象
const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);console.log(map1.get('b')); // 2
console.log(map2.get('b')); // 50
(2)List() 包裹数组
const { List } = require('immutable');const list1 = List([ 1, 2 ]);
const list2 = list1.push(3, 4, 5); // [1,2,3,4,5]
const list3 = list2.unshift(0); // [0,1,2,3,4,5]
const list4 = list1.concat(list2, list3); // [1,2,3,4,5,0,1,2,3,4,5]//push, set, unshift or splice 都可以直接用,返回一个新的immutable对象
(3)merge() 连接对象 | concat() 连接数组
const { Map, List } = require('immutable');const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
const map2 = Map({ c: 10, a: 20, t: 30 });
const obj = { d: 100, o: 200, g: 300 };const map3 = map1.merge(map2, obj);
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
(4)toJS() 把immutable对象转换为js对象
const { Map, List } = require('immutable');const deep = Map({ a: 1, b: 2, c: List([ 3, 4, 5 ]) });
console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'
(5)fromJS() 包裹 js对象转换为immutable对象
const { fromJS } = require('immutable');const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }console.log(nested2.getIn([ 'a', 'b', 'd' ])); // 6
//如果取一级属性 直接通过get方法,如果取多级属性 getIn(["a","b","c"]])// setIn 设置新的值
const nested3 = nested2.setIn([ 'a', 'b', 'd' ], "kerwin");
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: "kerwin" } } }// updateIn 回调函数更新
const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
相对较全的immutable
一些常用方法,都在这里给大家总结了,大家在项目中经常用就可以熟练掌握了。
immutable+Redux的开发方式
情况1:未使用immutable
时
下面的代码的情况十分危险,不建议这样用,因为一旦当newStateList
中的类型较为复杂(包含引用类型),且需要修改newStateList
时,就会发生报错,因为[...xxx, ...xxx]
是浅拷贝,会影响原来的状态。
情况2:使用immutable
时
通过store中传递过来的老状态prevState
先转化为immutable
对象,对深拷贝之后的对象,再进行修改等操作时,不会影响原状态,最后再通过toJS()
转换为js对象即可
Immutable的优势
1. 保证不可变(每次通过Immutable.js操作的对象都会返回一个新的对象) 2. 丰富的API 3. 性能好 (通过字典树对数据结构的共享)
Immutable的问题
1. 与原生JS交互不友好 (通过Immutable生成的对象在操作上与原生JS不同,如访问属性,myObj.prop1.prop2.prop3 => myImmutableMap.getIn([‘prop1’, ‘prop2’, ‘prop3’])。另外其他的第三方库可能需要的是一个普通的对象) 2. Immutable的依赖性极强 (一旦在代码中引入使用,很容易传播整个代码库,并且很难在将来的版本中移除) 3. 不能使用解构和对象运算符 (相对来说,代码的可读性差) 4. 不适合经常修改的简单对象 (Immutable的性能比原生慢,如果对象简单,并且经常修改,不适合用) 5. 难以调试 (可以采用 Immutable.js Object Formatter扩展程序协助) 6. 破坏JS原生对象的引用,造成性能低下 (toJs每次都会返回一个新对象)
感谢 暖眸的个人博客 - 编程圈 (bianchengquan.com)
react redux-immutable相关推荐
- 用 React+Redux+Immutable 做俄罗斯方块
俄罗斯方块是一直各类程序语言热衷实现的经典游戏,JavsScript的实现版本也有很多,用React 做好俄罗斯方块则成了我一个目标. 戳 https://chvin.github.io/react- ...
- 基于react + redux + ES6 + webpack + react-router的英雄联盟战绩查询应用
技术栈: react + redux + immutable + less + scss + ES6/7 + webpack + fetch + react-router按需加载 + react-tr ...
- react实战项目_React实战之React+Redux实现一个天气预报小项目
引言 经过一段时间的React学习,React和Vue的开发确实有很大的不同,但是都是MVVM框架,因此上手没有很大的难度,这次用React+Redux开发一个天气预报小项目.源码地址:https:/ ...
- 一个 react+redux 工程实例
在前几天的一篇文章中总结部分提到了学习过程中基础的重要性.当然,并不是不支持大家学习新的框架,这篇文章就分享一下react+redux工程实例. 一直在学习研究react.js,前前后后做了几次分享. ...
- 实例讲解基于 React+Redux 的前端开发流程
前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 star 数达 42000 +,超过了 jquery 的 39000+,也即将超过前几年比较火的an ...
- React Redux入门
目录 入门 我们应该什么时候使用? Redux库和工具 Redux Toolkit Redux DevTools 扩展 demo练习准备工作: 基础示例 Redux Toolkit示例 Redux术语 ...
- React+Redux开发实录(一)搭建工程脚手架
React+Redux开发实录(一)搭建工程脚手架 React+Redux开发实录(二)React技术栈一览 搭建工程脚手架 准备工作 安装node 安装git 安装一款前端IDE 推荐VSCode, ...
- 基于 react, redux 最佳实践构建的 2048
前段时间 React license 的问题闹的沸沸扬扬,搞得 React 社区人心惶惶,好在最终 React 团队听取了社区意见把 license 换成了 MIT.不管 React license ...
- React Redux 的一些基本知识点
一.React.createClass 跟 React.Component 的区别在于后者使用了ES6的语法,用constructor构造器来构造默认的属性和状态. 1. React.createCl ...
- 【视频】React redux toolkit创建状态切片
React redux toolkit创建状态切片
最新文章
- redmine升级了 ,6与18日同时发布2.0.3和1.4.4
- ASP.NET中String.IndexOf 方法的使用
- 超时,重试,熔断,限流
- Boost智能指针——weak_ptr
- 谷歌发布最新版安卓Android,谷歌正式除名华为,安卓12华为首发无望,但鸿蒙将迎难顶上!...
- python中面向对象空间时间_python基础学习Day15 面向对象、类名称空间、对象名称空间 (2)...
- django cookie、session
- Qt图形界面编程入门(信号和槽通信机制)
- mysql的条件语句_mysql条件语句
- bankeralgorithm.jar中没有主清单属性_怀旧服:迅击指环和其拉之怒属性一致,为何狂暴战用迅击更好...
- 数据中台对企业意义和作用有哪些
- 老兵不死:Radionomy正式宣布收购Winamp
- 三屏设置相关技术收集
- 基于qgis和arcgis进行CAD转GIS操作
- 全脑地图:单个记忆被拆分存储在多个相连的大脑区域
- 2008 r2 server sql 中文版补丁_Microsoft SQL Server 2008 r2 sp2补丁 64位 官方免费版
- Halcon常见错误
- 安卓系统网络服务器地址,安卓系统 云服务器地址
- Hadoop 2.X的安装与配置
- 【数据挖掘】数据挖掘概述