From 97aff0fbd645278859df57b9f079c970f252f7d0 Mon Sep 17 00:00:00 2001 From: liyang90 Date: Fri, 21 Oct 2016 14:42:31 +0800 Subject: [PATCH] Optimize connect() binding: Weapp use deep cloning in .setData() internally, so mappedState will never be shallow equal to data. In another word, shallowEqual(this.data, mappedState) will always return false. By tracking states in connect(), we can get patches between states, which can be later applied to .setData(). --- src/connect.js | 42 +++++++++++++++++++++++++++++------------- src/shallowEqual.js | 25 ------------------------- src/stateDiff.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 38 deletions(-) mode change 100644 => 100755 src/connect.js delete mode 100644 src/shallowEqual.js create mode 100755 src/stateDiff.js diff --git a/src/connect.js b/src/connect.js old mode 100644 new mode 100755 index 14904a9..9718afe --- a/src/connect.js +++ b/src/connect.js @@ -1,14 +1,16 @@ -import shallowEqual from './shallowEqual.js' +import stateDiff from './stateDiff.js' import warning from './warning.js' import wrapActionCreators from './wrapActionCreators.js' const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars -const defaultMapDispatchToProps = dispatch => ({dispatch}) +const defaultMapDispatchToProps = dispatch => ({ + dispatch +}) function connect(mapStateToProps, mapDispatchToProps) { const shouldSubscribe = Boolean(mapStateToProps) const mapState = mapStateToProps || defaultMapStateToProps - const app = getApp(); + const app = getApp() let mapDispatch if (typeof mapDispatchToProps === 'function') { @@ -27,11 +29,17 @@ function connect(mapStateToProps, mapDispatchToProps) { } const state = this.store.getState() - const mappedState = mapState(state, options); - if (!this.data || shallowEqual(this.data, mappedState)) { - return; + const mappedState = mapState(state, options) + const { + __state + } = this + const patch = stateDiff(mappedState, __state) + if (!patch) { + return } - this.setData(mappedState) + this.__state = mappedState + // only pass in updated data to .setData() + this.setData(patch) } const { @@ -44,9 +52,12 @@ function connect(mapStateToProps, mapDispatchToProps) { if (!this.store) { warning("Store对象不存在!") } - if(shouldSubscribe){ - this.unsubscribe = this.store.subscribe(handleChange.bind(this, options)) - handleChange.apply(this) + if (shouldSubscribe) { + this.__state = {} + this.unsubscribe = this.store.subscribe(() => { + handleChange.call(this, options) + }) + handleChange.call(this) } if (typeof _onLoad === 'function') { _onLoad.call(this, options) @@ -54,14 +65,19 @@ function connect(mapStateToProps, mapDispatchToProps) { } function onUnload() { + typeof this.unsubscribe === 'function' && this.unsubscribe() + // should no long receive state changes after .onUnload() + this.unsubscribe = null if (typeof _onUnload === 'function') { _onUnload.call(this) } - typeof this.unsubscribe === 'function' && this.unsubscribe() } - return Object.assign({}, pageConfig, mapDispatch(app.store.dispatch), {onLoad, onUnload}) + return Object.assign({}, pageConfig, mapDispatch(app.store.dispatch), { + onLoad, + onUnload + }) } } -module.exports = connect \ No newline at end of file +module.exports = connect diff --git a/src/shallowEqual.js b/src/shallowEqual.js deleted file mode 100644 index 040c7a4..0000000 --- a/src/shallowEqual.js +++ /dev/null @@ -1,25 +0,0 @@ -function shallowEqual(objA, objB) { - if (objA === objB) { - return true - } - - const keysA = Object.keys(objA) - const keysB = Object.keys(objB) - - if (keysA.length !== keysB.length) { - return false - } - - // Test for A's keys different from B. - const hasOwn = Object.prototype.hasOwnProperty - for (let i = 0; i < keysA.length; i++) { - if (!hasOwn.call(objB, keysA[i]) || - objA[keysA[i]] !== objB[keysA[i]]) { - return false - } - } - - return true -} - -module.exports = shallowEqual \ No newline at end of file diff --git a/src/stateDiff.js b/src/stateDiff.js new file mode 100755 index 0000000..c3854a7 --- /dev/null +++ b/src/stateDiff.js @@ -0,0 +1,29 @@ +const hasOwn = Object.prototype.hasOwnProperty + +function stateDiff(nextState, state) { + if (nextState === state) { + return null + } + + const patch = {} + + const keys = Object.keys(nextState) + const length = keys.length + let hasChanged = false + for (let i = 0; i < length; ++i) { + const key = keys[i] + const val = nextState[key] + if (!hasOwn.call(state, key) || val !== state[key]) { + patch[key] = val + hasChanged = true + } + } + + if (!hasChanged) { + return null + } + + return patch +} + +module.exports = stateDiff