immutable
1.下载并引入immutable
npm i -S immutable
import { List, Map, fromJS } from 'immutable'
2.介绍
-
Immutable Data就是一旦创建,就不能再被更改的数据。对Immutable对象的任何修改或添加删除操作都会返回一个新的Immutable对象 -
一般结合redux使用
-
使用原因:redux的reducer操作数据时都会进行深复制,这样数据少还好,一多性能就会降低
-
缺点:
需要重新学习api,有学习成本
容易与原生对象混淆:由于api与原生不同,混用的话容易出错
第3方组件库不支持,使用时,还需要转换
-
优点:
降低对象深复制带来的复杂度
节省内存
历史追溯性
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/updateInlet 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集合使用
-
安装redux-immutable
npm i -S redux-immutable -
它的合并是支持immutable对象合并
import { combineReducers } from 'redux-immutable' -
把所有的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.jsx
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
//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))
}