概述-----不可变数据
immutablejs库,它给我们创建了一新的js对象,此对象数据是不可变结构化数据。数据结构共享。 Immutable.js出自Facebook,是最流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,使用结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用。
- 因为在redux中,通过reducer函数对state处理过程中是一个对象的深复制。
- 采用immutable将会降低对象深复带来的复杂度
1.3、安装
- npm i -S immutable
1.4、常用API
- fromJs()------优点:会自动转换。
- 将纯js对象和数组通过递归进行深层转为List和Map
- 参数(json:any,reviver:()=>{})
- 如果没有提供reviver,默认行为会将数组转换为列表和对象到地图中。
- 将原始对象转换为Map
1 import { Map, List, fromJS } from 'immutable' 2 fromJS(): 原生js转immutable对象 3 const imState = fromJS({ 4 name: 'lisi', 5 users: ['aa', 'bb'] 6 })
List(): 原生array转List对象它可以把js中的数组对象转为 immutable中的List方法只能转换一维数组,如果是多维的,则不推荐Map:它可以把js中的json对象转为 immutable中的Map对象,Map方法只能转换json对象第1层,不会递归到后续层级中,用它转换的json对象如果层级较多,则推荐获取数据get/getIn
get /getIn
const obj = { id: 1, info: { name: 'lisi' , age: 20, arr: [1, 2] } }
// const state = fromJS(obj)
// console.log(state.get('name'))
// console.log(state.getIn(['name']))
// console.log(state.get('info').get('name')) 、、不推荐
// console.log(state.getIn(['info', 'name'])) 可以获取info对象下name的值
// console.log(state.getIn(['info', 'arr', 1])) 获取info下arr的索引为1的值
把immutable对象转为普通的js对象 immutable对象.toJS() =》 转为js对象
console.log(state.get('info').toJS())
// 把immutable对象转为普通的js对象 immutable对象.toJS() =》 转为js对象 // console.log(state.get('info').toJS())
修改 set/setIn update/updateIn 修改 set/setIn update/updateIn // set/setIn 对原数据进行覆盖 // update/updateIn 在原数据的基础上进行操作 update/updateIn可以实现set/setIn中的功能 // const obj = { id: 1, name: 'lisi', age: 20 } // const state = fromJS(obj) // const newState = state.set('name', '张三') // const newState = state.setIn(['name'], '张三 IN') // 在原数数据进行操作 // const newState = state.update('age', value => value + 1) // const newState = state.updateIn(['age'], value => value + 10) // 删除操作 delete/deleteIn/remove/removeIn -- 了解就可以 // const newState = state.remove('name') // 合并 // const state1 = fromJS({ id: 1, name: 'lisi'}) // const state2 = fromJS({ age: 20 }) // const newState = state1.merge(state2) // console.log(newState.toJS()) // 合并方案 // console.log(fromJS({...state1.toJS(),...state2.toJS()})) // // 对象比较 一般在react如果用,则是对于性能优化上所用 // const state1 = fromJS({ id: 1, name: 'lisi'}) // const state2 = fromJS({ id: 1, name: 'lisi'}) // // js比对,比对是地址,两个对象,地址肯定不同,所以返回false // // console.log(state1 === state2) // // immutable中它对于immutable对象提供一个方法 equals 比对immutable对象值是否相同,如果相同则返回true,反之false // console.log(state1.equals(state2)) //------------------------- List // const arr = [1, 2, 3, { id: 1, name: '李四' }] // // List转换,只转换第1层,不递归 // // const state = List(arr) // const state = fromJS(arr) // 获取 // console.log(state.get(1)) // console.log(state.getIn([1])) // console.log(state.getIn([3,'name'])) // 得到长度 属性 // console.log(state.size) // 修改 pop/shift/push/unshift/concat/splice /set/setIn/update/updateIn // const newState = state.update(2,v => v+3) // const newState = state.push(10) // const newState = state.concat(fromJS([10,20])) // const s1 = fromJS([1, 2]) // const s2 = fromJS([3, 4]) // const newState = fromJS([...s1, ...s2]) // console.log(newState.toJS()) // remove/removeIn // const s1 = fromJS([1, 2]) // const newState = s1.remove(0) // console.log(newState.toJS())
1.5 redux集成immutable
-
使用基本步骤
-
将store中的initState【同步的】,转为immutable对象。
-
在reducer中,返回一个新的immutable对象。使用immutable后,在reducer中处理数据无需进行深复制
-
采用update()将对应的数据进行修改。
-
组件当中依赖react-redux来获取store中的数据,但是获取的不是普通对象,需要用toJs()
😆组件中
import { connect } from 'react-redux'
@connect(
state => state.get('count').toJS(),
{
add() {
return { type: 'count_add', data: 10 }
}
}
)
class App extends Component {
render() {
return (
<div>
<h3>{this.props.num}</h3>
<button onClick={this.props.add}>修改</button>
</div>
)
}
}
redux中
import { createStore, applyMiddleware } from 'redux'
// 开启浏览器中的redux调试工具
import { composeWithDevTools } from '@redux-devtools/extension'
// 引入immutable库
import { fromJS } from 'immutable'
// 把普通json对象转为 immutable对象给redux
const initState = fromJS({
count: 100
})
const reducer = (state = initState, { type, data = 1 }) => {
if ('add' === type) {
// immutable对象的操作,会返回一个新的immutable对象
// 使用immutable后,在reducer中处理数据就无需进行深复制
return state.update('count', v => v + data)
}
// 返回的是一个immutable对象,它不是一个普通的json对象
return state
}
const store = createStore(reducer, composeWithDevTools())
export default store
1.6 多个reducer进行整合处理
将每一个reducer进行划分出去,放置在reducer中;
在里面进行初始值的设置,并且返回一个新immutable并导出;在store中有一个总reducer,是借助于immutable中的combineReducers进行整合
单个reducer // 引入immutable库 import { fromJS } from 'immutable' // 把普通json对象转为 immutable对象给redux const initState = fromJS({ films: [] }) const reducer = (state = initState, { type, data }) => { if ('film_add' === type) { // immutable对象的操作,会返回一个新的immutable对象 // 使用immutable后,在reducer中处理数据就无需进行深复制 return state.set('films', data) } // 返回的是一个immutable对象,它不是一个普通的json对象 return state } export default reducer
总reducer // import { createStore, applyMiddleware, combineReducers } from 'redux' import { createStore, applyMiddleware } from 'redux' // 开启浏览器中的redux调试工具 import { composeWithDevTools } from '@redux-devtools/extension' import thunk from 'redux-thunk' import { combineReducers } from 'redux-immutable' import count from '../reducer/count' import film from '../reducer/film' // 如果用redux中的 combineReducers 方法合并多个小的reducer,它返回的是一个 js普通对象,所以redux中用到了immutable,则一般不用内置此方法,而是安装一个 redux-immutable 库,则库中提供一个方法combineReducers,它就可以把合并后的对象也转为immutable对象,操作起来就变得统一了 const reducer = combineReducers({ count, film }) const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk))) export default store
1.7 immer的提出,优化setState操作
Immer是mobx的作者写的一个 immutable 库,核心实现是利用 ES6 的 Proxy,几乎以最小的成本实现了 js 的不可变数据结构,简单易用、体量小巧、设计巧妙,满足了我们对JS不可变数据结构的需求。
安装
npm i -S immer
主要实现将数据进行代理,可变化数据,但可共享结构;也就是说;一个数据对象中,代理此对象,更改对象中的数组,代理对象的数组和源对象数组不相等,但若未更改源对象中某一个对象的数据,该代理对象和源对象中的对象时相等的。即未发生结构变化。此外,produce,返回一个新的state,参数1:源数据,参数2:回调函数中的形参为元数据的浅复制对象
// 引入immer类 不可变结构变化数据,共享数据结构 import { produce } from 'immer' const currentState = { arr: [], obj: { id: 1 } } const newState = produce(currentState, draft => { draft.arr.push(1) }) console.log(newState.arr === currentState.arr) // false console.log(newState.obj === currentState.obj) // true
可以用来优化setState,也就是produce的写法二
- // 回调函数不能有返回值
// produce只有一个参数,为回调函数,写在setState中,它把draft映射到this.state对象代理 // 因为现在draft它是一个代理对象,可以直接去操作,不用像之前哪样key:value // 回调函数不能有返回值
import {produce} from 'immer'
class App extends Components{
const initState={
count:100
}
render(){
return(
<div>
<h3>{this.initState.count}</h3>
<button
onClick={()=>{
// this.setState(state => ({ count: state.count + 1 }))
// immer来优化setState写法
this.setState(
prodece(draft=>{
draft.count++
})
)
}}
>++</button>
</div>
)
}
}
1.8 使用immer来优化reducer
使用immerse来优化reducer,使用第一种写法,两个参数,第一个是初始数据,第二个是修改数据的回调函数
在store中
- 一定记得produce需要一个初始值,跟reduce一样
import {produce} from 'immer'
const initState={
count:100
}
const reducer=prodece((draft,{type,data})=>{
if(type==='count_add'){
//之前在这的深复制,不需要
draft.count+=data
}
},initState)
在组件调用中 import {connect} from 'react-redux' @connect(state=>state,{ add(){ return {type:'count_add',data:10} } }) class App extends Components{ render(){ <div> <h3>{this.props.count}</h3> <button onClick={this.props.add} ></button> </div> } }
浙公网安备 33010602011771号