摘要:的優(yōu)勢(shì)保證不可變每次通過(guò)操作的對(duì)象都會(huì)返回一個(gè)新的對(duì)象豐富的性能好通過(guò)字典樹(shù)對(duì)數(shù)據(jù)結(jié)構(gòu)的共享的問(wèn)題與原生交互不友好通過(guò)生成的對(duì)象在操作上與原生不同,如訪問(wèn)屬性,。
Immutable.js
Immutable的優(yōu)勢(shì)
1. 保證不可變(每次通過(guò)Immutable.js操作的對(duì)象都會(huì)返回一個(gè)新的對(duì)象) 2. 豐富的API 3. 性能好 (通過(guò)字典樹(shù)對(duì)數(shù)據(jù)結(jié)構(gòu)的共享)
Immutable的問(wèn)題
1. 與原生JS交互不友好 (通過(guò)Immutable生成的對(duì)象在操作上與原生JS不同,如訪問(wèn)屬性,myObj.prop1.prop2.prop3 => myImmutableMap.getIn([‘prop1’, ‘prop2’, ‘prop3’])。另外其他的第三方庫(kù)可能需要的是一個(gè)普通的對(duì)象) 2. Immutable的依賴性極強(qiáng) (一旦在代碼中引入使用,很容易傳播整個(gè)代碼庫(kù),并且很難在將來(lái)的版本中移除) 3. 不能使用解構(gòu)和對(duì)象運(yùn)算符 (相對(duì)來(lái)說(shuō),代碼的可讀性差) 4. 不適合經(jīng)常修改的簡(jiǎn)單對(duì)象 (Immutable的性能比原生慢,如果對(duì)象簡(jiǎn)單,并且經(jīng)常修改,不適合用) 5. 難以調(diào)試 (可以采用 Immutable.js Object Formatter擴(kuò)展程序協(xié)助) 6. 破壞JS原生對(duì)象的引用,造成性能低下 (toJs每次都會(huì)返回一個(gè)新對(duì)象)
原生Js遇到的問(wèn)題
// 場(chǎng)景一 var obj = {a:1, b:{c:2}}; func(obj); console.log(obj) //輸出什么?? // 場(chǎng)景二 var obj = ={a:1}; var obj2 = obj; obj2.a = 2; console.log(obj.a); // 2 console.log(obj2.a); // 2 代碼來(lái)源:https://juejin.im/post/5948985ea0bb9f006bed7472
// ajax1 this.props.a = { data: 1, } // ajax2 nextProps.a = { data: 1, } //shouldComponentUpdate() shallowEqual(this.props, nextProps) // false // 數(shù)據(jù)相同但是因?yàn)橐貌煌斐刹槐匾膔e-rederning
由于Js中的對(duì)象是引用類型的,所以很多時(shí)候我們并不知道我們的對(duì)象在哪里被操作了什么,而在Redux中,因?yàn)镽educer是一個(gè)純函數(shù),每次返回的都是一個(gè)新的對(duì)象(重新生成對(duì)象占用時(shí)間及內(nèi)存),再加上我們使用了connect這個(gè)高階組件,官方文檔中雖然說(shuō)react-redux做了一些性能優(yōu)化,但終究起來(lái),react-redux只是對(duì)傳入的參數(shù)進(jìn)行了一個(gè)淺比較來(lái)進(jìn)行re-redering(為什么不能在mapStateToProps中使用toJs的原因)。再進(jìn)一步,假如我們的state中的屬性嵌套了好幾層(隨著業(yè)務(wù)的發(fā)展),對(duì)于原來(lái)想要的數(shù)據(jù)追蹤等都變得極為困難,更為重要的是,在這種情況下,我們一些沒(méi)有必要的組件很可能重復(fù)渲染了多次。
總結(jié)起來(lái)就是以下幾點(diǎn)(問(wèn)題雖少,但都是比較嚴(yán)重的):
1. 無(wú)法追蹤Js對(duì)象 2. 項(xiàng)目復(fù)雜時(shí),reducer生成新對(duì)象性能低 3. 只做淺比較,有可能會(huì)造成re-redering不符合預(yù)期(多次渲染或不更新)
為什么不使用深比較
或許有人會(huì)疑惑,為什么不使用深比較來(lái)解決re-redering的問(wèn)題,答案很簡(jiǎn)單,因?yàn)橄姆浅>薮髜 想象一下,如果你的參數(shù)復(fù)雜且巨大, 對(duì)每一個(gè)進(jìn)行比較是多么消耗時(shí)間的一件事~
項(xiàng)目復(fù)雜后, 追蹤困難
使用Immutable之后,這個(gè)問(wèn)題自然而然就解決了。所謂的追蹤困難,無(wú)非就是因?yàn)閷?duì)象是mutable的,我們無(wú)法確定它到底何時(shí)何處被改變,而Immutable每次都會(huì)保留原來(lái)的對(duì)象,重新生成一個(gè)對(duì)象,(與redux的純函數(shù)概念一樣)。但也要注意寫(xiě)代碼時(shí)的習(xí)慣:
// javascript const obj = { a: 1 } function (obj) { obj.b = 2 ... } // Immutable const obj = Map({ a : 1 }) function (obj) { const obj2 = obj.set({ "b", 2 }) }
reducer生成新對(duì)象性能差
當(dāng)項(xiàng)目變得復(fù)雜時(shí),每一次action對(duì)于生成的新state都會(huì)消耗一定的性能,而Immutable.js在這方面的優(yōu)化就很好?;蛟S你會(huì)疑惑為什么生成對(duì)象還能優(yōu)化?請(qǐng)往下看~
在前面就講到,Immutable是通過(guò)字典樹(shù)來(lái)做==結(jié)構(gòu)共享==的
(圖片來(lái)自網(wǎng)絡(luò))
這張圖的意思就是
immutable使用先進(jìn)的tries(字典樹(shù))技術(shù)實(shí)現(xiàn)結(jié)構(gòu)共享來(lái)解決性能問(wèn)題,當(dāng)我們對(duì)一個(gè)Immutable對(duì)象進(jìn)行操作的時(shí)候,ImmutableJS會(huì)只clone該節(jié)點(diǎn)以及它的祖先節(jié)點(diǎn),其他保持不變,這樣可以共享相同的部分,大大提高性能。
re-rendering不符合預(yù)期
其實(shí)解決這個(gè)問(wèn)題是我們用Immutable的主要目的,先從淺比較說(shuō)起
淺比較引起的問(wèn)題在這之前已經(jīng)講過(guò),事實(shí)上,即使Immutable之后,connect所做的依然是淺比較,但因?yàn)镮mmutable每次生成的對(duì)象引用都不同,哪怕是修改的是很深層的東西,最后比較的結(jié)果也是不同的,所以在這里解決了第一個(gè)問(wèn)題,==re-rendering可能不會(huì)出現(xiàn)==。
但是, 我們還有第二個(gè)問(wèn)題, ==沒(méi)必要的re-rendering==,想要解決這個(gè)問(wèn)題,則需要我們?cè)俜庋b一個(gè)高階組件,在這之前需要了解下Immutable的 is API
// is() 判斷兩個(gè)immutable對(duì)象是否相等 immutable.is(imA, imB);
這個(gè)API有什么不同, ==這個(gè)API比較的是值,而不是引用==,So: 只要兩個(gè)值是一樣的,那么結(jié)果就是true
const a = Immutable.fromJS({ a: { data: 1, }, b: { newData: { data: 1 } } }) const target1 = a.get("a") const target2 = a.getIn(["b", "newData"]) console.log(Immutable.is(target1, target2)) //is比較的依據(jù)就是每個(gè)值的hashcode // 這個(gè)hashcode就相當(dāng)于每個(gè)值的一個(gè)ID,不同的值肯定有不同的ID,相同的ID對(duì)應(yīng)著的就是相同的值。
也就是說(shuō),對(duì)于下面的這種情況, 我們可以不用渲染
// ajax1 this.props.a = { data: 1, } // ajax2 nextProps.a = { data: 1, } //shouldComponentUpdate() Immutable.is(this.props, nextProps) // true
最后, 我們需要封裝一個(gè)高階組件來(lái)幫助我們統(tǒng)一處理是否需要re-rendering的情況
//baseComponent.js component的基類方法 import React from "react"; import {is} from "immutable"; class BaseComponent extends React.Component { constructor(props, context, updater) { super(props, context, updater); } shouldComponentUpdate(nextProps, nextState) { const thisProps = this.props || {}; const thisState = this.state || {}; nextState = nextState || {}; nextProps = nextProps || {}; if (Object.keys(thisProps).length !== Object.keys(nextProps).length || Object.keys(thisState).length !== Object.keys(nextState).length) { return true; } for (const key in nextProps) { if (!is(thisProps[key], nextProps[key])) { return true; } } for (const key in nextState) { if (!is(thisState[key], nextState[key])) { return true; } } return false; } } export default BaseComponent; 代碼來(lái)源鏈接:https://juejin.im/post/5948985ea0bb9f006bed7472
使用Immutable需要注意的點(diǎn)
1. 不要混合普通的JS對(duì)象和Immutable對(duì)象 (不要把Imuutable對(duì)象作為Js對(duì)象的屬性,或者反過(guò)來(lái)) 2. 對(duì)整顆Reudx的state樹(shù)作為Immutable對(duì)象 3. 除了展示組件以外,其他地方都應(yīng)該使用Immutable對(duì)象 (提高效率,而展示組件是純組件,不應(yīng)該使用) 4. 少用toJS方法 (一個(gè)是因?yàn)榉穸薎mmutable,另外則是操作非常昂貴) 5. 你的Selector應(yīng)該永遠(yuǎn)返回Immutable對(duì)象 (即mapStateToProps,因?yàn)閞eact-redux中是通過(guò)淺比較來(lái)決定是否re-redering,而使用toJs的話,每次都會(huì)返回一個(gè)新對(duì)象,即引用不同)
通過(guò)高階組件,將Immutable對(duì)象轉(zhuǎn)為普通對(duì)象傳給展示組件
1. 高階組件返回一個(gè)新的組件,該組件接受Immutable參數(shù),并在內(nèi)部轉(zhuǎn)為普通的JS對(duì)象 2. 轉(zhuǎn)為普通對(duì)象后, 新組件返回一個(gè)入?yún)槠胀▽?duì)象的展示組件
import React from "react" import { Iterable } from "immutable" export const toJS = WrappedComponent => wrappedComponentProps => { const KEY = 0 const VALUE = 1 const propsJS = Object.entries(wrappedComponentProps).reduce( (newProps, wrappedComponentProp) => { newProps[wrappedComponentProp[KEY]] = Iterable.isIterable( wrappedComponentProp[VALUE] ) ? wrappedComponentProp[VALUE].toJS() : wrappedComponentProp[VALUE] return newProps }, {} ) return}
import { connect } from "react-redux" import { toJS } from "./to-js" import DumbComponent from "./dumb.component" const mapStateToProps = state => { return { // obj is an Immutable object in Smart Component, but it’s converted to a plain // JavaScript object by toJS, and so passed to DumbComponent as a pure JavaScript // object. Because it’s still an Immutable.JS object here in mapStateToProps, though, // there is no issue with errant re-renderings. obj: getImmutableObjectFromStateTree(state) } } export default connect(mapStateToProps)(toJS(DumbComponent))參考
Immutable.js 以及在 react+redux 項(xiàng)目中的實(shí)踐
Using Immutable.JS with Redux
不變應(yīng)萬(wàn)變-Immutable優(yōu)化React
React-Redux分析
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101588.html
摘要:前言是一個(gè)非常實(shí)用的狀態(tài)管理庫(kù),對(duì)于大多數(shù)使用庫(kù)的開(kāi)發(fā)者來(lái)說(shuō),都是會(huì)接觸到的。在使用享受其帶來(lái)的便利的同時(shí),我們也深受其問(wèn)題的困擾。只支持同步,讓狀態(tài)可預(yù)測(cè),方便測(cè)試。粗暴地級(jí)聯(lián)式刷新視圖使用優(yōu)化。 前言 Redux是一個(gè)非常實(shí)用的狀態(tài)管理庫(kù),對(duì)于大多數(shù)使用React庫(kù)的開(kāi)發(fā)者來(lái)說(shuō),Redux都是會(huì)接觸到的。在使用Redux享受其帶來(lái)的便利的同時(shí), 我們也深受其問(wèn)題的困擾。 redux...
摘要:是一個(gè)前端頁(yè)面制作工具,方便產(chǎn)品,運(yùn)營(yíng)和視覺(jué)的同學(xué)迅速開(kāi)發(fā)簡(jiǎn)單的前端頁(yè)面,從而可以解放前端同學(xué)的工作量。支持恢復(fù)現(xiàn)場(chǎng)功能關(guān)閉頁(yè)面配置不丟失支持操作。提供了一個(gè)方法,用于的拆分。就是發(fā)出的通知,表示應(yīng)該要發(fā)生變化了。 pagemaker是一個(gè)前端頁(yè)面制作工具,方便產(chǎn)品,運(yùn)營(yíng)和視覺(jué)的同學(xué)迅速開(kāi)發(fā)簡(jiǎn)單的前端頁(yè)面,從而可以解放前端同學(xué)的工作量。此項(xiàng)目創(chuàng)意來(lái)自網(wǎng)易樂(lè)得內(nèi)部項(xiàng)目nfop中的page...
摘要:前端日?qǐng)?bào)精選大前端公共知識(shí)梳理這些知識(shí)你都掌握了嗎以及在項(xiàng)目中的實(shí)踐深入貫徹閉包思想,全面理解閉包形成過(guò)程重溫核心概念和基本用法前端學(xué)習(xí)筆記自定義元素教程阮一峰的網(wǎng)絡(luò)日志中文譯回調(diào)是什么鬼掘金譯年,一個(gè)開(kāi)發(fā)者的好習(xí)慣知乎專 2017-06-23 前端日?qǐng)?bào) 精選 大前端公共知識(shí)梳理:這些知識(shí)你都掌握了嗎?Immutable.js 以及在 react+redux 項(xiàng)目中的實(shí)踐深入貫徹閉包思...
摘要:為什么使用的核心是將組件化,由數(shù)據(jù)驅(qū)動(dòng)的展現(xiàn)。僅僅使用進(jìn)行開(kāi)發(fā)的痛點(diǎn)組件嵌套層級(jí)深,回調(diào)地獄。遵守容器組件與展示組件分離的原則。 為什么使用redux React的核心是將UI組件化,由數(shù)據(jù)驅(qū)動(dòng)UI的展現(xiàn)。但是如何管理數(shù)據(jù)模型、組件與數(shù)據(jù)模型之間的通信,react并沒(méi)有很好的解決方案。Redux由flux演變而來(lái),同時(shí)簡(jiǎn)化了Flux的流程。 僅僅使用react進(jìn)行開(kāi)發(fā)的痛點(diǎn) 組件嵌套...
摘要:數(shù)據(jù)結(jié)構(gòu)類型擴(kuò)展相對(duì)之類的強(qiáng)類型語(yǔ)言,有一點(diǎn)很大的區(qū)別就是,數(shù)據(jù)結(jié)構(gòu)只有與,并且都是動(dòng)態(tài)可變的,而有等數(shù)據(jù)結(jié)構(gòu)。所以,為了能在中也使用這些數(shù)據(jù)結(jié)構(gòu),就應(yīng)運(yùn)而生。擴(kuò)充了中的不可變集合,即一旦創(chuàng)建就不能改變的數(shù)據(jù)類型。 js 數(shù)據(jù)結(jié)構(gòu)類型擴(kuò)展:immutable-js 相對(duì) java、.net 之類的強(qiáng)類型語(yǔ)言,js 有一點(diǎn)很大的區(qū)別就是,數(shù)據(jù)結(jié)構(gòu)只有 array 與 object,并且都...
閱讀 1995·2021-11-22 19:20
閱讀 2640·2021-11-22 13:54
閱讀 1969·2021-09-04 16:40
閱讀 1826·2021-08-13 11:54
閱讀 2669·2019-08-30 15:55
閱讀 3468·2019-08-29 13:51
閱讀 531·2019-08-29 11:09
閱讀 3010·2019-08-26 14:06