immutable

170 阅读3分钟

immutable

1.下载并引入immutable

npm i -S immutable

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

2.介绍

  1. Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象

  2. 一般结合redux使用

  3. 使用原因:redux的reducer操作数据时都会进行深复制,这样数据少还好,一多性能就会降低

  4. 缺点:

    需要重新学习api,有学习成本

    容易与原生对象混淆:由于api与原生不同,混用的话容易出错

    第3方组件库不支持,使用时,还需要转换

  5. 优点:

    降低对象深复制带来的复杂度

    节省内存

    历史追溯性

3. 常用API

  • 类似于原生js中的 数组 数组 ==> List, List转换它只会转换第1层

  • 类似于原生js中的 对象 {} ==> Map, Map转换它只会转换第1层,不建议去用

    let state = Map(obj)

  • fromJS 它会自动深层转换

    let state = fromJS(obj)

  • 获取immutable对象中的数据 get/getIn

    console.log(state.get('name'))

    console.log(state.getIn(['name']))

  • 深层调用时,建议使用getIn

    console.log(state.get('info').get('n'))

    console.log(state.getIn(['info','n']))

  • 修改 -- 修改后会返回一个新的immutable对象 set/setIn/update/updateIn

    let state = fromJS({ id: 1, name: '张三', info: { n: 1000 } })

const map1 = Map({ a: 1, b: 2, c: 3})
const map2 = Map({ a: 1, b: 2, c: 3})
​
console.log(map1 === map2) // false
console.log(map1.equals(map2)) // true
map.toJS() // 把map转为js对象
const list1 = List([1, 2]);
const list2 = list1.push(3, 4, 5);
// 获取值
console.log(list2.get(0));
​
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const list3 = list2.concat(list1);
console.log(list3.toArray())
fromJS(): 原生js转immutable对象
const imState = fromJS({
  name: 'lisi',
  users: ['aa', 'bb']
})
​
# 获取数据
imState.get('name')
console.log(imState.get('users').get(1))
console.log(imState.getIn(['users', 0]))
toJS(): immutable对象转原生js   不推荐使用
const state = imState.toJS()
console.log(state);
set/setIn/update/updateIn  修改数据
const newState = imState.set('name', 'zhangsan')
const newState = imState.setIn(['name'], 'zhangsan')
const newState = imState.update('count', value => value + 1)
const newState = imState.updateIn(['count'], value => value + 1)

4.redux和immutable集合使用

  1. 安装redux-immutable

    npm i -S redux-immutable

  2. 它的合并是支持immutable对象合并

    import { combineReducers } from 'redux-immutable'

  3. 把所有的reducer数据转换为immutable对象

    import {fromJS} from 'immutable'
    const defaultState = fromJS({})
    
//App.jsx
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Film from './components/Film'// state它是一个immutable对象
// connect参数1:返回一个原生的js对象
@connect(state => state.get('num').toJS(), {
  add(n = 1) {
    return { type: 'add', data: n }
  }
})
class App extends Component {
  render() {
    return (
      <div>
        <h3>{this.props.count}</h3>
        <button onClick={() => this.props.add()}>+++</button>
        <hr />
        <Film />
      </div>
    )
  }
}
​
export default App  
​
//Film.jsximport React, { Component } from 'react'
import { connect } from 'react-redux'
//一次性把所有的按需导出的模块导入过来,并且使用as起一个别名,actions是一个对象
import * as actions from '@/action/filmAction'@connect(state => state.get('film').toJS(),actions)
 class Film extends Component {
    componentDidMount() {
        this.props.getFilmListAction()
    }
  render() {
    return (
      <div>
        <ul>
            {/* 条件渲染 */}、
            {this.props.films.length === 0 ? (
                <li>加载中....</li>
            ) : (
                this.props.films.map(item => <li key={item.id}> {item.title} </li>)
            )}
        </ul>
      </div>
    )
  }
}
export default Film
//store/index.js
import { createStore, applyMiddleware } from 'redux'
// 此库不是必须的,但是用它,可以让我们多个redux模块,统一为immutable对象
import { combineReducers } from 'redux-immutable'import thunk from 'redux-thunk' 
import { composeWithDevTools } from '@redux-devtools/extension'import num from '@/reducer/num'
import film from '@/reducer/film'const reducer = combineReducers({
    num,
    film
})
​
const store = createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
export default store
//Child.js
import React, { Component } from 'react'
import _ from "lodash";
import { fromJS, is } from 'immutable';
export default class Child extends Component {
    shouldComponentUpdate(nextProps,nextState){
        let newProps = fromJS(nextProps)
        let oldProps = fromJS(this.props)
        return !is(oldProps,newProps)
    }
  render() {
    return (
      <div>
        <h3> {this.props.num.value} </h3>
      </div>
    )
  }
}
​
//Film,js
import React, { Component } from 'react'
import { connect } from 'react-redux'
//一次性把所有的按需导出的模块导入过来,并且使用as起一个别名,actions是一个对象
import * as actions from '@/action/filmAction'@connect(state => state.get('film').toJS(),actions)
 class Film extends Component {
    componentDidMount() {
        this.props.getFilmListAction()
    }
  render() {
    return (
      <div>
        <ul>
            {/* 条件渲染 */}、
            {this.props.films.length === 0 ? (
                <li>加载中....</li>
            ) : (
                this.props.films.map(item => <li key={item.id}> {item.title} </li>)
            )}
        </ul>
      </div>
    )
  }
}
export default Film
//filmAction.js
import axios from "axios";
import { FILMTYPE_ADDFILMS } from "@/store/types/filmType";
​
const createActionFilms = data => ({ type:FILMTYPE_ADDFILMS,data})
//电影列表数据网络获取
export const getFilmListAction = () => async dispatch => {
    let ret = await axios.get('/mock/films.json')
    //发布给redux更新他的数据源
    dispatch(createActionFilms(ret.data))
}