摘要:的優勢保證不可變每次通過操作的對象都會返回一個新的對象豐富的性能好通過字典樹對數據結構的共享的問題與原生交互不友好通過生成的對象在操作上與原生不同,如訪問屬性,。
Immutable.js
Immutable的優勢
1. 保證不可變(每次通過Immutable.js操作的對象都會返回一個新的對象) 2. 豐富的API 3. 性能好 (通過字典樹對數據結構的共享)
Immutable的問題
1. 與原生JS交互不友好 (通過Immutable生成的對象在操作上與原生JS不同,如訪問屬性,myObj.prop1.prop2.prop3 => myImmutableMap.getIn([‘prop1’, ‘prop2’, ‘prop3’])。另外其他的第三方庫可能需要的是一個普通的對象) 2. Immutable的依賴性極強 (一旦在代碼中引入使用,很容易傳播整個代碼庫,并且很難在將來的版本中移除) 3. 不能使用解構和對象運算符 (相對來說,代碼的可讀性差) 4. 不適合經常修改的簡單對象 (Immutable的性能比原生慢,如果對象簡單,并且經常修改,不適合用) 5. 難以調試 (可以采用 Immutable.js Object Formatter擴展程序協助) 6. 破壞JS原生對象的引用,造成性能低下 (toJs每次都會返回一個新對象)
原生Js遇到的問題
// 場景一 var obj = {a:1, b:{c:2}}; func(obj); console.log(obj) //輸出什么?? // 場景二 var obj = ={a:1}; var obj2 = obj; obj2.a = 2; console.log(obj.a); // 2 console.log(obj2.a); // 2 代碼來源:https://juejin.im/post/5948985ea0bb9f006bed7472
// ajax1 this.props.a = { data: 1, } // ajax2 nextProps.a = { data: 1, } //shouldComponentUpdate() shallowEqual(this.props, nextProps) // false // 數據相同但是因為引用不同而造成不必要的re-rederning
由于Js中的對象是引用類型的,所以很多時候我們并不知道我們的對象在哪里被操作了什么,而在Redux中,因為Reducer是一個純函數,每次返回的都是一個新的對象(重新生成對象占用時間及內存),再加上我們使用了connect這個高階組件,官方文檔中雖然說react-redux做了一些性能優化,但終究起來,react-redux只是對傳入的參數進行了一個淺比較來進行re-redering(為什么不能在mapStateToProps中使用toJs的原因)。再進一步,假如我們的state中的屬性嵌套了好幾層(隨著業務的發展),對于原來想要的數據追蹤等都變得極為困難,更為重要的是,在這種情況下,我們一些沒有必要的組件很可能重復渲染了多次。
總結起來就是以下幾點(問題雖少,但都是比較嚴重的):
1. 無法追蹤Js對象 2. 項目復雜時,reducer生成新對象性能低 3. 只做淺比較,有可能會造成re-redering不符合預期(多次渲染或不更新)
為什么不使用深比較
或許有人會疑惑,為什么不使用深比較來解決re-redering的問題,答案很簡單,因為消耗非常巨大~ 想象一下,如果你的參數復雜且巨大, 對每一個進行比較是多么消耗時間的一件事~
項目復雜后, 追蹤困難
使用Immutable之后,這個問題自然而然就解決了。所謂的追蹤困難,無非就是因為對象是mutable的,我們無法確定它到底何時何處被改變,而Immutable每次都會保留原來的對象,重新生成一個對象,(與redux的純函數概念一樣)。但也要注意寫代碼時的習慣:
// 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生成新對象性能差
當項目變得復雜時,每一次action對于生成的新state都會消耗一定的性能,而Immutable.js在這方面的優化就很好。或許你會疑惑為什么生成對象還能優化?請往下看~
在前面就講到,Immutable是通過字典樹來做==結構共享==的
(圖片來自網絡)
這張圖的意思就是
immutable使用先進的tries(字典樹)技術實現結構共享來解決性能問題,當我們對一個Immutable對象進行操作的時候,ImmutableJS會只clone該節點以及它的祖先節點,其他保持不變,這樣可以共享相同的部分,大大提高性能。
re-rendering不符合預期
其實解決這個問題是我們用Immutable的主要目的,先從淺比較說起
淺比較引起的問題在這之前已經講過,事實上,即使Immutable之后,connect所做的依然是淺比較,但因為Immutable每次生成的對象引用都不同,哪怕是修改的是很深層的東西,最后比較的結果也是不同的,所以在這里解決了第一個問題,==re-rendering可能不會出現==。
但是, 我們還有第二個問題, ==沒必要的re-rendering==,想要解決這個問題,則需要我們再封裝一個高階組件,在這之前需要了解下Immutable的 is API
// is() 判斷兩個immutable對象是否相等 immutable.is(imA, imB);
這個API有什么不同, ==這個API比較的是值,而不是引用==,So: 只要兩個值是一樣的,那么結果就是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比較的依據就是每個值的hashcode // 這個hashcode就相當于每個值的一個ID,不同的值肯定有不同的ID,相同的ID對應著的就是相同的值。
也就是說,對于下面的這種情況, 我們可以不用渲染
// ajax1 this.props.a = { data: 1, } // ajax2 nextProps.a = { data: 1, } //shouldComponentUpdate() Immutable.is(this.props, nextProps) // true
最后, 我們需要封裝一個高階組件來幫助我們統一處理是否需要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; 代碼來源鏈接:https://juejin.im/post/5948985ea0bb9f006bed7472
使用Immutable需要注意的點
1. 不要混合普通的JS對象和Immutable對象 (不要把Imuutable對象作為Js對象的屬性,或者反過來) 2. 對整顆Reudx的state樹作為Immutable對象 3. 除了展示組件以外,其他地方都應該使用Immutable對象 (提高效率,而展示組件是純組件,不應該使用) 4. 少用toJS方法 (一個是因為否定了Immutable,另外則是操作非常昂貴) 5. 你的Selector應該永遠返回Immutable對象 (即mapStateToProps,因為react-redux中是通過淺比較來決定是否re-redering,而使用toJs的話,每次都會返回一個新對象,即引用不同)
通過高階組件,將Immutable對象轉為普通對象傳給展示組件
1. 高階組件返回一個新的組件,該組件接受Immutable參數,并在內部轉為普通的JS對象 2. 轉為普通對象后, 新組件返回一個入參為普通對象的展示組件
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 項目中的實踐
Using Immutable.JS with Redux
不變應萬變-Immutable優化React
React-Redux分析
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101588.html
摘要:前言是一個非常實用的狀態管理庫,對于大多數使用庫的開發者來說,都是會接觸到的。在使用享受其帶來的便利的同時,我們也深受其問題的困擾。只支持同步,讓狀態可預測,方便測試。粗暴地級聯式刷新視圖使用優化。 前言 Redux是一個非常實用的狀態管理庫,對于大多數使用React庫的開發者來說,Redux都是會接觸到的。在使用Redux享受其帶來的便利的同時, 我們也深受其問題的困擾。 redux...
摘要:是一個前端頁面制作工具,方便產品,運營和視覺的同學迅速開發簡單的前端頁面,從而可以解放前端同學的工作量。支持恢復現場功能關閉頁面配置不丟失支持操作。提供了一個方法,用于的拆分。就是發出的通知,表示應該要發生變化了。 pagemaker是一個前端頁面制作工具,方便產品,運營和視覺的同學迅速開發簡單的前端頁面,從而可以解放前端同學的工作量。此項目創意來自網易樂得內部項目nfop中的page...
摘要:前端日報精選大前端公共知識梳理這些知識你都掌握了嗎以及在項目中的實踐深入貫徹閉包思想,全面理解閉包形成過程重溫核心概念和基本用法前端學習筆記自定義元素教程阮一峰的網絡日志中文譯回調是什么鬼掘金譯年,一個開發者的好習慣知乎專 2017-06-23 前端日報 精選 大前端公共知識梳理:這些知識你都掌握了嗎?Immutable.js 以及在 react+redux 項目中的實踐深入貫徹閉包思...
摘要:為什么使用的核心是將組件化,由數據驅動的展現。僅僅使用進行開發的痛點組件嵌套層級深,回調地獄。遵守容器組件與展示組件分離的原則。 為什么使用redux React的核心是將UI組件化,由數據驅動UI的展現。但是如何管理數據模型、組件與數據模型之間的通信,react并沒有很好的解決方案。Redux由flux演變而來,同時簡化了Flux的流程。 僅僅使用react進行開發的痛點 組件嵌套...
摘要:數據結構類型擴展相對之類的強類型語言,有一點很大的區別就是,數據結構只有與,并且都是動態可變的,而有等數據結構。所以,為了能在中也使用這些數據結構,就應運而生。擴充了中的不可變集合,即一旦創建就不能改變的數據類型。 js 數據結構類型擴展:immutable-js 相對 java、.net 之類的強類型語言,js 有一點很大的區別就是,數據結構只有 array 與 object,并且都...
閱讀 1974·2021-11-22 19:20
閱讀 2618·2021-11-22 13:54
閱讀 1932·2021-09-04 16:40
閱讀 1814·2021-08-13 11:54
閱讀 2628·2019-08-30 15:55
閱讀 3456·2019-08-29 13:51
閱讀 519·2019-08-29 11:09
閱讀 2997·2019-08-26 14:06