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.state
return (
<div>
Son组件:{value}
<p>姓名:{user.name}</p>
<p>年龄:{user.age}</p>
<p>爱好:{user.hobby.h1}</p>
</div>
)
}
}