immutable.js 是 Facebook 开源的一个项目,用于实现 javascript 的数据不可变,解决引用带来的反作用。javascript
不变的数据(Immutable Data )一旦建立就没法更改,从而能够简化应用程序开发,进行防护性复制,并可使用简单的逻辑实现高级的备忘和更改检测技术。持久数据提供了一个可变API,该API不会就地更新数据,而是始终产生新的更新数据,也就是说,对 Immutable 对象的任何修改或添加删除操做都会返回一个新的 Immutable 对象。java
// 原来的写法
let foo = {a: {b: 1}};
let bar = foo;
bar.a.b = 2;
console.log(foo.a.b); // 打印 2
console.log(foo === bar); // 打印 true
// 使用 immutable.js 后
import Immutable from 'immutable';
foo = Immutable.fromJS({a: {b: 1}});
bar = foo.setIn(['a', 'b'], 2); // 使用 setIn 赋值
console.log(foo.getIn(['a', 'b'])); // 使用 getIn 取值,打印 1
console.log(foo === bar); // 打印 false
复制代码
immutable.js提供了一些永久不可变数据结构,包括:react
做用:将一个js数据转换为Immutable类型的数据
用法:fromJS(value, reviver)
简介:value是要转变的数据,reviver是要作的操做。第二个参数可不填,默认状况会将数组准换为List类型,将对象转换为Map类型,其他不作操做。git
let bar = { a: 10, b: [10, 20, 30],c: 40,d: 10, e: [10, 20, 30],f: {g:10,h:{i:20}}}
let demo = Immutable.fromJS(bar,
function (key, value, path) {
console.log(Immutable.isKeyed(value),'key='+key,'value='+value,'path=',path)
})
//打印结果
//false "key=b" "value=Seq [ 10, 20, 30 ]" "path=" ["b"]
//false "key=e" "value=Seq [ 10, 20, 30 ]" "path=" ["e"]
//true "key=h" "value=Seq { "i": 20 }" "path=" (2) ["f", "h"]
//true "key=f" "value=Seq { "g": 10, "h": undefined }" "path=" ["f"]
//true "key=" "value=Seq { "a": 10, "b": undefined, "c": 40, "d": 10, "e": undefined, "f": undefined }" "path=" []
复制代码
做用:将一个Immutable List类型数据转换为JS类型的数据
用法:value.toJS()es6
做用:对两个对象进行比较 用法:is(first,second) 简介:能够比较原始类型(如字符串和数字),Immutable.js集合(如Map和List),以及任何经过提供和方法实现的自定义对象,比较0和-0值是相同的。和js中对象的比较不一样,在js中比较两个对象比较的是地址,可是在Immutable中比较的是这个对象hashCode和valueOf,只要两个对象的hashCode相等,值就是相同的,避免了深度遍历,提升了性能。github
做用:数据的合并,新数据与旧数据对比ajax
此示例为Map结构,List与Map原理相同:npm
const Map1 = Immutable.fromJS({a:111,b:222,c:{d:333,e:444}});
const Map2 = Immutable.fromJS({a:111,b:222,c:{e:444,f:555}});
const Map3 = Map1.merge(Map2); //旧数据中不存在的属性直接添加,就数据中已存在的属性用新数据中的覆盖
//Map {a:111,b:222,c:{e:444,f:555}}
const Map4 = Map1.mergeDeep(Map2); //深合并,新旧数据中同时存在的的属性为新旧数据合并以后的数据
//Map {a:111,b:222,c:{d:333,e:444,f:555}}
const Map5 = Map1.mergeWith((oldData,newData,key)=>{ //自定义浅合并,可自行设置某些属性的值
if(key === 'a'){
return 666;
}else{
return newData
}
},Map2);
//Map {a:666,b:222,c:{e:444,f:555}}
复制代码
做用:获取数据结构中的数据redux
做用:判断是否存在某一个key数组
做用:判断是否存在某一个value
Immutable.fromJS
而不是 Immutable.Map
或 Immutable.List
来建立对象,这样能够避免 Immutable 和原生对象间的混用,例如,Map & Immutable.Map。map.get('key')
而不是 map.key
,array.get(0)
而不是 array[0]
。另外 Immutable 每次修改都会返回新对象,也很容易忘记赋值。安装redux-immutable的命令 npm install redux-immutable。
安装immutable的命令 npm install immutable。 redux-immutable提供一个combineReducers()函数,将stroe中最外层的reducer中的state转化为immutable对象(这里涉及到reducer的拆分,拆分用到了与redux中同名的combineReducers()方法)
好比如今我建立了一个Header的组件(代码有删减)
import React,{Component} from 'react';
import {connect} from 'react-redux';
import {CSSTransition} from 'react-transition-group';
class Header extends Component{
render() {
const {home,focused,list,login,handleInputFocus,handleInputBlur,handleHomeActive,logout} = this.props
return (
<HeaderWrapper>
<SearchWrapper>
<CSSTransition
in={focused}
timeout={200}
classNames="slide"
>
<NavSearch
className={focused?'focused':''}
onFocus={()=>handleInputFocus(list)}
/>
</CSSTransition>
{this.getListArea()}
</SearchWrapper>
</HeaderWrapper>
)
}
getListArea() {
const {focused,list,page,totalPage} = this.props;
const newList = list.toJS() //immutable对象装换成js对象
const pageList = []
//ajax请求发送获取数据以后再显示,保证key值得有效
if(newList.length){
for(let i=(page-1)*10;i<page*10;i++) {
pageList.push(
<SearchInfoItem key={newList[i]}>{newList[i]}</SearchInfoItem>
)
}
}
if(focused) { //鼠标聚焦输入框时展现热门搜索的列表
return (
<SearchInfo>
<SearchInfoTitle>
热门搜索
</SearchInfoTitle>
<SearchInfoList>
{pageList}
</SearchInfoList>
</SearchInfo>
)
}else{
return null
}
}
}
const mapState = (state)=>{
return {
home:state.getIn(['header','home']), //获取state中保存的数据
focused:state.getIn(['header','focused']),
list:state.getIn(['header','list']),
}
}
const mapDispatch = (dispatch)=>{
return {
handleHomeActive(value){
dispatch(changeHomeActive(value))
},
handleInputFocus(list) {
(list.size===0) && dispatch(actionCreators.getList())
dispatch(actionCreators.searchFocus())
},
}
}
export default connect(mapState,mapDispatch)(Header)
}
复制代码
Header组件目录下的reducer.js的内容
import * as constants from './constants'
import {fromJS} from 'immutable'
const defaultState = fromJS({ //将数据转化成immutable数据
home:true,
focused:false,
mouseIn:false,
list:[],
page:1,
totalPage:1
})
export default(state=defaultState,action)=>{
switch(action.type){
case constants.SEARCH_FOCUS:
return state.set('focused',true) //更改immutable数据
case constants.CHANGE_HOME_ACTIVE:
return state.set('home',action.value)
case constants.SEARCH_BLUR:
return state.set('focused',false)
case constants.CHANGE_LIST:
// return state.set('list',action.data).set('totalPage',action.totalPage)
//merge效率更高,执行一次改变多个数据
return state.merge({
list:action.data,
totalPage:action.totalPage
})
case constants.MOUSE_ENTER:
return state.set('mouseIn',true)
case constants.MOUSE_LEAVE:
return state.set('mouseIn',false)
case constants.CHANGE_PAGE:
return state.set('page',action.page)
default:
return state
}
}
复制代码
根目录下的reducer.js文件
import {combineReducers} from 'redux-immutable'
import {reducer as headerReducer} from '../common/Header/store'
//当项目中有多个组件时,reducer能够拆分为多个reducer,而后在最外层使用combineReducers将各个reducer组合在一块儿。这样代码逻辑比较清晰
const reducer = combineReducers({
header:headerReducer,
})
export default reducer
复制代码
引用的文章: