不可变数据库之immutable.js

216 阅读3分钟

前言

  • 简介: 每次修改一个 immutable 对象时都会创建一个新的不可变的对象,在新对象上操作并不会影响到原对象的数据
  • 安装: npm i immutabel
  • 引入: import { Map, List, ... } from 'immutable'
  • 优化性能的方式
    • JSON.parse(JSON.stringify(xxx)): 不能有undefined(有undefined的话那个属性会拷贝不过来)
    • 递归深复制: 一层层复制,性能不好,占用内存
    • immutable: 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享

Map

基本用法

import { Map } from 'immutable'

let obj = {
  name: 'kerwin',
  age: 100
}

// 普通对象 --> immutable对象
let oldImmuObj = Map(obj)
// set设置属性值,设置完后返回一个新的对象
let newImmuObj = oldImmuObj.set('name', 'xiaoming')

// get获取属性值
newImmuObj.get('name')

// immutable对象 --> 普通对象
newImmuObj.toJS()

react中的使用: 方式1(在初始化的时候就使用immutable对象)

import React, { Component } from 'react'
import { Map } from 'immutable'

export default class App extends Component {
  state = {
    info: Map({
      name: 'kerwin',
      age: 100
    })
  }

  render() {
    return (
      <div>
        <button onClick={() => {
          this.setState({
            // 可以链式调用
            info: this.state.info.set('name', 'xiaoming').set('age', 18)
          })
        }}>click</button>
      </div>
    )
  }
}

react中的使用: 方式2(要修改是数据的时候再转化成immutable对象,改完再转回来)

import React, { Component } from 'react'
import { Map } from 'immutable'

export default class App extends Component {
  state = {
    info: {
      name: 'kerwin',
      age: 100
    }
  }

  render() {
    return (
      <div>
        <button onClick={() => {
          let old = Map(this.state.info)
          let newImmu = old.set('name', 'xiaoming').set('age', 18)
          this.setState({
            info: newImmu.toJS()
          })
        }}>click</button>
      </div>
    )
  }
}

监听部分属性是否发生改变

import React, { Component } from 'react'
import { Map } from 'immutable'
export default class App extends Component {
  state = {
    // ===== 外面一层Map并不能影响到里面到对象,需要每一层都加上Map =====
    // info: Map({
    //   name: 'kerwin',
    //   select: 'aa',
    //   filter: Map({
    //     text: '',
    //     up: true,
    //     down: false
    //   })
    // })
    // ===== fromJS: 相当于给每一层对象都加上Map,每一层数组都加上List =====
    info: fromJS({
      name: 'kerwin',
      select: 'aa',
      filter: {
        text: '',
        up: true,
        down: false
      }
    })
  }

  render() {
    return (
      <div>
        <button onClick={()=>{
          this.setState({
            // 修改name和select后,filter并没有发生改变
            info: this.state.info.set('name', 'xiaoming').set('select', 'dwadwa')
          })
        }}>click</button>
        <Child filter={this.state.info.get('filter')}/>
      </div>
    )
  }
}

class Child extends Component{
  shouldComponentUpdate(nextProps, nextState) {
    // 修改name和select后,filter并没有发生改变
    if(this.props.filter === nextProps.filter){
      return false
    }
    return true
  }
}

List

基本使用

import { List } from 'immutable'

// 数组对应的方法 List 都有
let arr = List([1, 2, 3])
// 以下修改不会影响老的对象结构
let arr2 = arr.push(4)
let arr3 = arr2.concat([5, 6, 7])

react中的使用

import React, { Component } from 'react'
import { List } from 'immutable'

export default class App extends Component {
  state = {
    favor: List(['aaa', 'bbb', 'ccc'])
  }

  render() {
    return (
      <div>
        {
          this.state.favor.map(item =>
            <li key={item}>{item}</li>
          )
        }
      </div>
    )
  }
}

fromJS、toJS

import { Map, List, fromJS, toJS } from 'immutable'

// info: Map({
//   name: 'kerwin',
//   selectList: List(['a', 'b']),
//   filter: Map({
//     text: '',
//     up: true,
//     down: false
//   })
// })
// fromJS: 转化成immutable对象(相当于给每一层对象都加上Map,每一层数组都加上List)
let info = fromJS({
  name: 'kerwin',
  selectList: ['a', 'b'],
  filter: {
    text: '',
    up: true,
    down: false
  }
})

// toJS: 转化成普通对象
let newInfo = info.toJS()

setIn、updateIn

state = {
  info: fromJS({
    name: 'kerwin',
    location: {
      province: '辽宁',
      city: '大连'
    },
    favor: ['读书', '看报', '写代码']
  })
}

setIn: 修改对象

this.setState({
  // 使用set
  info: this.state.info
    .set('name', 'xiaomng')
    .set('location', this.state.info.get('location').set('city', '沈阳'))
})

this.setState({
  // 使用setIn: 参数1(要修改的属性),参数2(要更新的值)
  info: this.state.info
    .setIn(['name'], 'xiaomng')
    // 修改 info.location.city 值
    .setIn(['location', 'city'], '沈阳')
})

updateIn: 修改数组

this.setState({
  // 使用set
  info: this.state.info.set('favor', this.state.info.get('favor').splice(index, 1))
})

this.setState({
  // 使用updateIn
  info: this.state.info.updateIn(['favor'], list => list.splice(index, 1))
})

参考