在項目中常常會遇到一些問題,好比把一個對象賦值給另一個對象後,如何實現修改被賦值的對象而原對象不變;通常作法是copy,而copy又分爲shallowCopy(淺拷貝)和 deepCopy(深拷貝);shallowCopy對於層級比較深的對象來講然並*用,那麼只能用deepCopy來避免上面遇到的狀況,但deepCopy是一個很耗性能的操做。再好比使用react技術棧來作項目時,常常須要咱們手工去判斷某些組件是否須要從新渲染來減小咱們可愛又傲嬌的DOM操做,react提供shouldComponentUpdate鉤子函數來判斷該組件樹是否須要從新渲染,在該鉤子函數中通常使用淺比較和深比較來判斷該組件樹是否須要從新渲染;若是隻是淺比較,只須要PureRender就能知足,那麼須要深比較呢? 上面瞎逼逼一堆廢話無非是想說用immutable的好處,它能解決這些問題呀,它的共享結構多牛比呀,零學習成本讓你開開心心玩時間旅行。react
immutable據說是Facebook 工程師 Lee Byron 花費 3 年時間打造,與 React 同期出現,但沒有被默認放到 React 工具集裏(React 提供了簡化的 Helper);immutable一旦被建立終身不會變化,每次增長或修改仍是刪除都是返回一個新的對象;immutable內部採用Structure Sharing(結構共享)來避免每一次deepCopy的性能損耗,每一次增刪改都只會改變當前節點和父節點並返回一個新對象。git
據說 Immutable 能夠給 React 應用帶來數十倍的提高,我的感受10應該達不到,可是確實提高很多效率和避免因對象被修改而致使的錯誤,雖然能夠在項目中使用Object.assign或者lodash來避免原對象被修改而致使的一些錯誤,可是這兩貨也有不少缺點,Object.assign只能深拷貝一個層級,並且你會發現滿屏的Object.assign,對於處女座的做者確定是不能容忍此事的發生;Immutable提供了is方法,由於Immutable內部使用的是Trie 數據結構,因此只須要比較hashCode或valueOf來避免深度比較。github
下面介紹一下immutable中經常使用的map和list的一些基礎用法,固然還有不少其餘類型( Collection、Set、Record、Seq等),本文介紹一些經常使用API讓讀者瞭解使用immutable基本是零學習成本,固然你也能夠選擇功能更單一的seamless-immutable,代碼庫很是小,壓縮後下載只有 2K:redux
將js轉換成immutable對象:數組
immutable.Listbash
immutable.Map數據結構
在react中使用immutable時應該注意避免出現toJS操做,由於toJS和fromJS是把整個數據結構遍歷一遍,還要建立新對象來保存值,是很耗性能的操做;建議項目中所有使用immutable,數據從服務請求回來轉化成immutable再給redux,只有在提交數據和使用第三方不支持immutable組件或者插件時才轉化成原生對象;下面是使用immutable的開發流程。less
//操做對象以前拷貝
let newState = Object.assign({}, this.state.obj, {
'a': 'test'
});
//操做以前數組的拷貝
let newArr = [...arr, ...arr1];
複製代碼
//使用immutable來初始化狀態
this.state = Map(obj);
//改變state的值
this.setState(this.state.set('a', 'test'));
複製代碼
當react中使用了redux來進行狀態管理時如何在項目中使用immutable,因爲 Redux 中內置的 combineReducers和 reducer 中的 initialState 都爲原生的 Object 對象,因此不能和 Immutable 原生搭配使用;可是能夠經過重寫combineReducers或者直接使用redux-immutablejs,本文介紹如何使用redux-immutablejs。函數
按照 Redux 的工做流,咱們從建立 store 開始。Redux 的 createStore 能夠傳遞多個參數,前兩個是: reducers 和 initialState工具
const initialState = immutable.Map({
list: [],
card: {
id: '',
title: '',
desc: ''
}
});
複製代碼
在reducer裏把之前的Obejct.assagin操做所有去掉,轉換成immutable對象。
export default function list(state = initialState, action) {
let card;
switch (action.type) {
case types.EDIT_ENTRY:
let lists = state.get('list');
lists = lists.push(action.newData.get('data'));
card = action.newData.get('card');
return state.set('list', lists).set('card', card);
case types.VALUE_CHANGE:
return state.set('card', action.card);
case types.ADD:
return state.set('card', action.card);
default:
return state;
}
}
複製代碼
在action裏面的全部對象都是immutable,爲了區分原生對象,請不要在有的地方使用js原生對象,有的地方使用immutable對象,這樣每每會拔苗助長,容易混淆和immutable和原生轉換時性能的消耗。
export function editData() {
let card = Map({
id: '',
title: '',
desc: ''
});
return { type: types.ADD, card };
}
複製代碼
若是你不傳遞 initialState,redux-immutable也會幫助你在 store 初始化的時候,經過每一個子 reducer 的初始值來構建一個全局 Map 做爲全局 state。固然,這要求你的每一個子 reducer 的默認初始值是 immutable的。只須要引入redux-immutable就能夠在redux裏面使用immutable了,
import {
combineReducers
} from 'redux-immutable';
import list from './list/listRedux';
const rootReducer = combineReducers({
list
});
export default rootReducer;
複製代碼
function mapStateToProps(state) {
return {
listMain: state.get('list')
};
}
export default connect(mapStateToProps)(Main);
複製代碼
immutable不是全部的項目都適合使用,在業務簡單數據關聯性不復雜等條件下使用反而增長了項目的複雜度,經過上面的開發流程你們也應該看出了immutable侵入性仍是槓槓的,因此若是是項目起初考慮上immutable是能夠的;可是對於老項目中使用就的考慮一下得失了。