本文轉(zhuǎn)自我的博客閱讀原文替废。
一覽
整合各個子的reducer
redux官方提供的combineReducers
只支持原生JS的形式,所以這里要用redux-immutable提供的combineReducers
來代替螟炫。
import {combineReducers} from 'redux-immutable'
import dish from './dish'
import menu from './menu'
import cart from './cart'
// 整合各個子的reducer
const rootReducer = combineReducers({dish, menu, cart})
export default rootReducer
reducer中的initialState肯定也需要初始化成immutable類型
// Map里面?zhèn)鞯氖且粋€原生JS對象,初始化reducer中的initialState時建議用Map方法而不是fromJS方法惭婿,效率更高
const initialState = Immutable.Map({})
export default function menu(state = initialState, action) {
switch (action.type) {
case SET_ERROR:
return state.set('isError', true)
}
}
將immutable的數(shù)據(jù)映射到組件的props中
state成為了immutable類型不恭,所以mapStateToProps
也要改寫成immutable的取值方法。
function mapStateToProps(state) {
return {
menuList: state.getIn(['dish', 'list']), //使用get或者getIn來獲取state中的變量
CartList: state.getIn(['dish', 'cartList'])
}
}
immutable數(shù)據(jù)類型檢驗(yàn)
這就需要我們 import 專門針對immutable類型進(jìn)行校驗(yàn)的庫:react-immutable-proptypes
财饥,使用方法基本上和普通的PropTypes一致:
propTypes: {
oldListTypeChecker: React.PropTypes.instanceOf(Immutable.List),
anotherWay: ImmutablePropTypes.list,
requiredList: ImmutablePropTypes.list.isRequired,
mapsToo: ImmutablePropTypes.map,
evenIterable: ImmutablePropTypes.iterable
}
// 與此同時换吧,產(chǎn)生defaultProps的地方應(yīng)該為:
fromJS({
prop1: xxx,
prop2: xxx,
prop3: xxx
}).toObject()
裝飾shouldComponentUpdate
減少頁面無意義渲染的次數(shù)是immutable提升react效率的重中之重。
import pureRender from "pure-render-immutable-decorator"
// @pureRender會幫你實(shí)現(xiàn)shouldComponentUpdate钥星。如果在這個鉤子中還有自己的邏輯的話沾瓦,請參看官方文檔
@pureRender
class List extends Component {
constructor(props, context) {
super(props, context)
}
render() {
return (
<div> </div>
)
}
}
上面用到decorator,在js的babel loader里面谦炒,新增plugins: [‘transform-decorators-legacy’]贯莺。
這個模塊下面還有一個不用immutable的可以對原生JS對象進(jìn)行深比較的模塊(pure-render-deepCompare-decorator)。
進(jìn)階
immutable.js使用過程中的一些注意點(diǎn)
- fromJS和toJS會深度轉(zhuǎn)換數(shù)據(jù)宁改,隨之帶來的開銷較大缕探,盡可能避免使用,單層數(shù)據(jù)轉(zhuǎn)換使用Map()和List()
- js是弱類型还蹲,但Map類型的key必須是string5摹(也就是我們?nèi)≈凳且胓et('1')而不是get(1))
- 所有針對immutable變量的增刪改必須左邊有賦值,因?yàn)樗胁僮鞫疾粫淖冊瓉淼闹得蘸埃皇巧梢粋€新的變量
- 獲取深層深套對象的值時不需要做每一層級的判空(JS中如果不判空會報錯潭兽,immutable中只會給undefined)
- immutable對象直接可以轉(zhuǎn)JSON.stringify(),不需要顯式手動調(diào)用toJS()轉(zhuǎn)原生
- 判斷對象是否是空可以直接用size
- 調(diào)試過程中要看一個immutable變量中真實(shí)的值,可以chrome中加斷點(diǎn)斗遏,在console中使用.toJS()方法來查看
高階組件封裝
對于使用immutable.js的項(xiàng)目山卦,在應(yīng)用公共組件的時候,由于公共組件的內(nèi)部實(shí)現(xiàn)一定是原生JS數(shù)據(jù)诵次,所以我們只能傳遞原生JS數(shù)據(jù)到公共組件账蓉,但是如果轉(zhuǎn)換成了原生JS數(shù)據(jù),就又會出現(xiàn)"React.addons.PureRenderMixin提供的shouldComponentUpdate()是淺比較"問題逾一,對此可以使用下面的高階組件進(jìn)行封裝铸本。
/* 定義高階組件 */
import {React} from 'base'
// 通過Immutable.is 封裝過的 shouldComponentUpdate
import {shouldComponentUpdate} from '../immutable-pure-render-decorator'
export default ComposedComponent => {
return class extends React.Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = shouldComponentUpdate.bind(this)
}
render() {
const props = this.props.toJS ? this.props.toJS() : this.props
return <ComposedComponent { ...this.props} { ...props} />
}
}
}
/* 使用高階組件 */
import highComponent from '../../../../widgets/libs/utils/highComponent'
// 公共組件
import Dialog from '@alife/dialog'
function mapStateToProps(state) {
}
function mapDispatchToProps(dispatch) {
}
// 通過高階組件封裝
export default connect(mapStateToProps, mapDispatchToProps)(highComponent(Dialog))
immutable常用API
//Map() 原生object轉(zhuǎn)Map對象 (只會轉(zhuǎn)換第一層,注意和fromJS區(qū)別)
immutable.Map({name:'danny', age:18})
//List() 原生array轉(zhuǎn)List對象 (只會轉(zhuǎn)換第一層嬉荆,注意和fromJS區(qū)別)
immutable.List([1,2,3,4,5])
//fromJS() 原生js轉(zhuǎn)immutable對象 (深度轉(zhuǎn)換归敬,會將內(nèi)部嵌套的對象和數(shù)組全部轉(zhuǎn)成immutable)
immutable.fromJS([1,2,3,4,5]) //將原生array --> List
immutable.fromJS({name:'danny', age:18}) //將原生object --> Map
//toJS() immutable對象轉(zhuǎn)原生js (深度轉(zhuǎn)換,會將內(nèi)部嵌套的Map和List全部轉(zhuǎn)換成原生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用于深層結(jié)構(gòu)訪問
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+Redux+ImmutableJS進(jìn)行SPA開發(fā)
React移動web極致優(yōu)化
immutable.js 在React椅亚、Redux中的實(shí)踐以及常用API簡介
Immutable.js 以及在 react+redux 項(xiàng)目中的實(shí)踐