Immutable.js原理分析
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
Immutable.js的使用
安装
cnpm i immutable --save
Map的操作
import React from 'react';
import ReactDOM from 'react-dom';
import {Map} from 'immutable';//声明一个对象,这个对象要设置为不可被修改的对象
const state = {value: 'hello',list: ['html','css','js']
}//将要设置不可更改的对象,传入到Map()方法中,会返回一个新的state对象
const imState = Map(state)//将state对象设置为不可被修改的对象后,使用 get('key') 方法取值
console.log(imState.get('value'))//使用set()方法修改值,修改后会返回一个新的对象,原来的对象数据没有变化
const newImState = imState.set('value','world')console.log(imState.get('value'))
console.log(newImState.get('value'))ReactDOM.render(<div>hello</div>,document.getElementById('root'));
List的操作
import React from 'react';
import ReactDOM from 'react-dom';
import {List} from 'immutable';//声明一个数据,要将该数组设置为不可更改的数组
const arry = [1,2,3]//将数组传入 List() 中即可设置不可更改的数组对象
const imList = List(arry)//对imList做追加操作,不会对原数组做修改,会返回一个新的数组对象
const newImList = imList.push(4)console.log(imList.size,newImList.size)ReactDOM.render(<div>hello</div>,document.getElementById('root'));
fromJS的操作
import React from 'react';
import ReactDOM from 'react-dom';
import {fromJS} from 'immutable';//声明一个不可更改的对象
const state = {value: 'hello',list: ['html','css','js'],obj: {x: 1,y: {z: 2}}
}//把state传入的fromJS()中
const imState = fromJS(state)//获取imState中的值
console.log(imState.get('value'))//修改imState中的值,修改对象中的第一层属性的值,可以使用 set() 方法
const newState = imState.set('value','world')
console.log(newState.get('value'))//修改imState中更深层次的数据,需要使用 setIn() 或 updateIn() 方法
//setIn() 可以直接赋值,参数1为对象属性的层级结构,按照层级顺序编写到数组中;参数2为要赋的值
const newState1 = imState.setIn(['obj','y','z'],100)
//updateIn() 可以对原始值做修改后再返回新的值,参数1同上,参数2为修改值时用的回调函数,回调函数的参数为对象原始值
const newState2 = imState.updateIn(['obj','y','z'], val => val + 1)//获取深层对象结构的值,使用 getIn() 方法
console.log(newState1.getIn(['obj','y','z']))
console.log(newState2.getIn(['obj','y','z']))ReactDOM.render(<div>hello</div>,document.getElementById('root'));
在redux中使用immutable
使用Map操作
第1步:创建store
import {createStore} from 'redux'
import reducer from './reducer'const store = createStore(reducer)export default store
第2步:创建reducer
import {Map} from 'immutable'//使用Map()来创建原始对象,创建的原始对象为不可更改的对象
const defaultState = Map({value: ''
})const reducer = (state = defaultState, action)=>{//在执行修改state的代码中,使用 set() 方法完成修改操作,返回一个新的对象if(action.type === 'change_value'){return state.set('value',action.value)}return state
}export default reducer
第3步:创建App.js文件,用于修改redux中的数据
import React, { Component } from 'react'
import store from './store'
import Son from './Son'export default class App extends Component {constructor() {super()this.state = store.getState()store.subscribe(()=>{this.setState(store.getState())})}//文本框输入事件handleInput(e){let action = {type: 'change_value',value: e.target.value}store.dispatch(action)}render() {return (<div><input value={this.state.value} onChange={this.handleInput.bind(this)}></input><Son></Son></div>)}
}
第4步:创建Son.js用于实时显示redux中的数据
import React, { Component } from 'react'
import store from './store'export default class Son extends Component {constructor(){super()//此时使用store.getState()获取的数据为immutable处理后的对象,要使用get()方法获取具体值this.state = {value: store.getState().get('value')}store.subscribe(()=>{this.setState({value: store.getState().get('value')})})}render() {return (<div>Son组件:{this.state.value}</div>)}
}
使用fromJS操作
App.js代码
import React, { Component } from 'react'
import store from './store'
import Son from './Son'export default class App extends Component {constructor() {super()this.state = {value: '',name: '',age: 0,h1: ''}}//提交事件handleSubmit(){let action = {type: 'reg_user',value: this.state.value,name: this.state.name,age: this.state.age,h1: this.state.h1}store.dispatch(action)}render() {return (<div><div>普通值:<input value={this.state.value} onChange={(e)=>{this.setState({value: e.target.value})}}></input></div><div>姓名:<input value={this.state.name} onChange={(e)=>{this.setState({name: e.target.value})}}></input></div><div>年龄:<input value={this.state.age} onChange={(e)=>{this.setState({age: e.target.value})}}></input></div><div>爱好:<input value={this.state.h1} onChange={(e)=>{this.setState({h1: e.target.value})}}></input></div><button onClick={this.handleSubmit.bind(this)}>提交</button><hr /><Son></Son></div>)}
}
store.js代码
import {createStore} from 'redux'
import reducer from './reducer'const store = createStore(reducer)export default store
reducer.js代码
import {fromJS} from 'immutable'//使用Map()来创建原始对象,创建的原始对象为不可更改的对象
const defaultState = fromJS({value: '',user: {name: '',age: 0,hobby: {h1: ''}}
})const reducer = (state = defaultState, action)=>{//使用fromJS中的 setIn() 方法修改数据if(action.type === 'reg_user'){return state.setIn(['user','name'],action.name).setIn(['user','age'],action.age).setIn(['user','hobby','h1'],action.h1).set('value',action.value)}return state
}export default reducer
Son.js代码
import React, { Component } from 'react'
import store from './store'export default class Son extends Component {constructor(){super()//此时store.getState()获取到数据为复杂类型,要使用getIn()方法const storeState = store.getState();this.state = {value: storeState.get('value'),user: {name: storeState.getIn(['user','name']),age: storeState.getIn(['user','age']),hobby: {h1: storeState.getIn(['user','hobby','h1'])}}}//监听store中的数据更新store.subscribe(()=>{const storeState2 = store.getState();this.setState({value: storeState2.get('value'),user: {name: storeState2.getIn(['user','name']),age: storeState2.getIn(['user','age']),hobby: {h1: storeState2.getIn(['user','hobby','h1'])}}})})}render() {let {value,user} = this.statereturn (<div>Son组件:{value}<p>姓名:{user.name}</p><p>年龄:{user.age}</p><p>爱好:{user.hobby.h1}</p></div>)}
}