let obj = { a: 1, arr: [1, 2] }; let obj1 = obj; //淺複製 obj1.a = 2 console.log(obj) // { a:2, arr: [1,2] }; //一樣的方式 let obj = { a: 1, arr: [1, 2] }; let obj2 = deepCopy(obj); //深複製 obj2.a = 2 console.log(obj) // { a:1, arr: [1,2] };
由於JavaScript存儲對象都是存地址的,因此淺複製會致使 obj 和 obj1
指向同一塊內存地址,大概的示意圖以下。而深複製通常都是開闢一塊新的內存地址,將原對象的各個屬性逐個複製出去。html
深複製只有一層,以後爲淺複製(除非再次使用Object.assign嵌套方式賦值)react
let obj = { a: 1, arr: [1, 2] }; let obj1 = Object.assign({}, obj); obj1.a = 2 //不變 console.log(obj) // { a:1, arr: [1,2] }; let obj = { a: { b: 20 }, arr: [1, 2] }; let obj1 = Object.assign({}, obj); obj1.a.b = 2; //除非再次使用Object.assign嵌套方式賦值 //變化 console.log(obj) // { a:{b:2}, arr: [1,2] };
第一種方式git
//recduer.js(cart)第一種方式 case types.CART_PUT_MAIN + '_SUCCESS': //更新數據 carts = state.main.carts; // carts 選中的id數組 id = action.param.id; newState = { ...state, main:{ ...state.main, itemObj:{ ...state.main.itemObj, [id]:{ ...state.main.itemObj[id], quantity:action.param.quantity } } } }; sum = sumCommon(carts, newState.main.itemObj); newState = { ...newState, main:{ ...newState.main, ...sum } }; return newState;
讓咱們來看一下對數據層的變化:es6
componentWillReceiveProps(nextProps){ console.log(nextProps); //next:顧名思義是接收到的next->props,輸出的是上面方法中的newState的值 console.log(this.props); //cur:是當前的props的值,由於使用的是類immutable的方式,因此數據不變; }
第二種方式github
//recduer.js(cart)第一種方式 case types.CART_PUT_MAIN + '_SUCCESS': newState = Object.assign({}, state); carts = newState.main.carts; // carts 選中的id數組 id = action.param.id; //淺複製 newState.main.itemObj[id].quantity = action.param.quantity;; sum = sumCommon(carts, newState.main.itemObj); newState = Object.assign({}, newState, { main: Object.assign({}, newState.main, sum) }); return newState;
讓咱們來再來看一下對數據層的變化:api
componentWillReceiveProps(nextProps){ console.log(nextProps); //next:顧名思義是接收到的next->props,輸出的是上面方法中的newState的值 console.log(this.props); //cur:是當前的props的值,而這個因爲淺複製,這個值被改變了 }
爲了讓數據變化更加可測,咱們應當使用深複製相關,讓咱們本身的數據更加安全數組
直接{...obj}賦值屬於淺複製,在修改值時{...obj,a:1}就起到了類深複製的效果
更新一個 Object ,則:安全
let obj = { a: 0, b: 20, } obj = {...obj, a: obj.a + 1}
而不是:babel
obj.a = obj.a + 1
一樣的爲了不對 Object 的 in-place editing,數組也是同樣:性能
let arr = [ { id: 1,a: 1} ] arr = [...arr, { id: 2,a: 2} ]
而不是:
let arr = [ { id: 1, a:1} ] arr.push({ id: 2, a,2});
以這樣的方式,無需 Immutable.js ,咱們可讓應用程序狀態是 不可變(Immutable) 的。
let obj = { a: 20, arr: [1, 2] }; let obj1 = { ...obj }; //於obj1=obj同樣 // 保持統一,儘可能不要使用這樣的替換(有可能形成沒必要要的麻煩) obj1.a = 2 //...儘可能使用這樣的賦值形式 obj1 = { ...obj1 , a:2 } //深複製 console.log(obj) // { a:20, arr: [1,2] }; console.log(obj1) // { a:2, arr: [1,2] };
...與Object.assign屬於一個道理(這裏和層級相關)
//你能夠將其轉化爲 let obj = { a: { b: 20 }, arr: [1, 2] }; let obj1 = obj obj1 = Object.assign({}, obj1, { a: Object.assign({}, obj1.a,{b:2}) }); console.log(obj) //{ a:{b:20}, arr: [1,2] } console.log(obj) //{ a:{b:2}, arr: [1,2] } 因此儘可能使用...代替Object.assign
以前方式的多層嵌套
//深複製(類immutable) newState = { ...state, main:{ ...state.main, itemObj:{ ...state.main.itemObj, [id]:{ ...state.main.itemObj[id], prop:action.param.props_str, product_id:action.param.product_id, price:action.param.price } } } }; //淺複製 newState.main.itemObj[id].prop = action.param.props_str; //immutable.js方式 ...參考immutable的api吧,暫時就不提供了--!
簡單的說就是數據變化,比較先後兩次的數據是否相同,判斷是否從新render;不然你的父容器一改變數據,全部的子組件都從新渲染了,爲了增長性能請使用pureRender;
(封裝好的PureRender以下:)
'use strict'; import { is } from 'immutable'; let hasOwnProperty = Object.prototype.hasOwnProperty; function shallowEqual(objA, objB) { if (objA === objB || is(objA, objB)) { return true; } if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } let keysA = Object.keys(objA); let keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } let bHasOwnProperty = hasOwnProperty.bind(objB); for (let i = 0; i < keysA.length; i++) { if (!bHasOwnProperty(keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { return false; } } return true; } function shallowCompare(instance, nextProps, nextState) { return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState); } function shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this, nextProps, nextState); } function pureRenderDecorator(component) { component.prototype.shouldComponentUpdate = shouldComponentUpdate; } module.exports = pureRenderDecorator; /*使用方式*/ import pureRender from 'pure-render-decorator'; //babel配置中引入一個transform-decorators-legacy插件 @pureRender class XXX extends React.Component { //... }
PureRender的使用要求:對於子組件須要什麼參數傳遞什麼,不要把一大塊無用的數據引入,不然兩次傳入的this.props可能始終會不同,致使PureRender無效