3.React 之 immutable 和 redux-immutable

2,877 阅读4分钟

immutable 和redux-immutable

我们在状态管理时,是不允许直接修改state对象的,像之前这种代码

import { ADD_ITEM, CHANGE_INPUT, DELETE_ITEM } from './actionTypes'

const defaultState = {
  inputValue: '123',
  list: []
}

export default (state = defaultState, action) => {
  if (action.type === CHANGE_INPUT) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.inputValue = action.value
    return newState
  }
  if (action.type === ADD_ITEM) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)
    newState.inputValue = ''
    return newState
  }
  if (action.type === DELETE_ITEM) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.list.splice(action.index, 1)
    return newState
  }
  return state
}

这种原生js的形式因为state是无法直接更改的,因此往往需要对对象做深层拷贝并返回新对象的形式,有时候会增加性能损耗,这时候可以使用immutable来使数据不可被更改

当时用immutable.js 时, 使用 {formJS} ,使 JS对象 转化为 immutable对象,更改数据时,使用 get 与 set 方法 获取 和 设置 值

import * as actionTypes from './actionTypes'
import {fromJS} from 'immutable'
const defaultState =fromJS({
    focused: false
})

const headerReducer =  (state = defaultState, action) => {
    if(action.type === actionTypes.FOCUS_INPUT) {
        return  state.set('focused', true);
    }
    if(action.type === actionTypes.BLUR_INPUT) {
        return  state.set('focused', false);
    }
    return state;
}

export default headerReducer;

此时由于原本的redux合并的combineReducers只支持原生可改变的state值,所以还需要借助redux-immutable来从state取出一个immutable 对象,如下

// import {combineReducers} from 'redux'; 从这里取 state 是一个js对象
import {combineReducers} from 'redux-immutable';// 从这里取  state 是一个immutable对象

import { reducer as headerReducer } from '../components/Header/store'
import { reducer as homeReducer } from '../pages/home/store'
import { reducer as detailReducer } from '../pages/detail/store'
import { reducer as loginReducer } from '../pages/login/store'

// 类似于vuex的module合并,会将这部分的内容封装至不同的参数下单独管理即header:{header单独的state状态管理}
export default combineReducers({
  header: headerReducer,
  home: homeReducer,
  detail: detailReducer,
  login: loginReducer
})

由于使用了新的redux-immutable来从reducer中取得了一个immutable对象,所以在组件中也不能用原生js点操作符来取数据了,所以

const mapStateToProps = (state) => {
    return {
        // focused: state.header.focused  // 全是js 对象的时候这么调用
        // focused: state.header.get('focused') //state是一个js 对象 的时候(只用immutable时)这么调用
        // focused: state.get('header').get('focused') //state 和 focused 是immutable对象
        focused: state.getIn(['header', 'focused']) //state 和 focused 是immutable对象
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        handleInputFocus() {
            dispatch(actionCreators.focusInput())
        },
        handleInputBlur() {
            dispatch(actionCreators.blurInput())
        }
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);

immutable.js使用过程中的一些注意点

  • fromJS和toJS会深度转换数据,随之带来的开销较大,尽可能避免使用,单层数据转换使用Map()和List()
  • js是弱类型,但Map类型的key必须是string!(也就是我们取值是要用get('1')而不是get(1))
  • 所有针对immutable变量的增删改必须左边有赋值,因为所有操作都不会改变原来的值,只是生成一个新的变量
  • 获取深层深套对象的值时不需要做每一层级的判空(JS中如果不判空会报错,immutable中只会给undefined)
  • immutable对象直接可以转JSON.stringify(),不需要显式手动调用toJS()转原生
  • 判断对象是否是空可以直接用size
  • 调试过程中要看一个immutable变量中真实的值,可以chrome中加断点,在console中使用.toJS()方法来查看

immutable常用API

//Map()  原生object转Map对象 (只会转换第一层,注意和fromJS区别)
immutable.Map({name:'danny', age:18})
//List()  原生array转List对象 (只会转换第一层,注意和fromJS区别)
immutable.List([1,2,3,4,5])
//fromJS()   原生js转immutable对象  (深度转换,会将内部嵌套的对象和数组全部转成immutable)
immutable.fromJS([1,2,3,4,5])    //将原生array  --> List
immutable.fromJS({name:'danny', age:18})   //将原生object  --> Map
//toJS()  immutable对象转原生js  (深度转换,会将内部嵌套的Map和List全部转换成原生js)
immutableData.toJS();
//查看List或者map大小  
immutableData.size  或者 immutableData.count()
// is()   判断两个immutable对象是否相等
immutable.is(imA, imB);
//merge()  对象合并
var imA = immutable.fromJS({a:1,b:2});
var imA = immutable.fromJS({c:3});
var imC = imA.merge(imB);
console.log(imC.toJS())  //{a:1,b:2,c:3}
//增删改查(所有操作都会返回新的值,不会修改原来值)
var immutableData = immutable.fromJS({
    a:1,
    b:2,
    c:{
        d:3
    }
});
var data1 = immutableData.get('a') //  data1 = 1  
var data2 = immutableData.getIn(['c', 'd']) // data2 = 3   getIn用于深层结构访问
var data3 = immutableData.set('a' , 2);   // data3中的 a = 2
var data4 = immutableData.setIn(['c', 'd'], 4);   //data4中的 d = 4
var data5 = immutableData.update('a',function(x){return x+4})   //data5中的 a = 5
var data6 = immutableData.updateIn(['c', 'd'],function(x){return x+4})   //data6中的 d = 7
var data7 = immutableData.delete('a')   //data7中的 a 不存在
var data8 = immutableData.deleteIn(['c', 'd'])   //data8中的 d 不存在

相关连接

最近在学习react开发,整理几篇笔记方便自己查询使用,下面是连接地址

1.React 之 react-transition-group

2.React之 redux、react-redux、redux-thunk

3.React 之 immutable 和 redux-immutable

4.React 之react-router-dom

5.React 之 react-loadable

6.React 基础记录

7.React 使用less等预处理器配置