diff --git a/.babelrc b/.babelrc index 002b4aa..7a8bc5a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["env"] + "presets": ["env"], + "plugins": ["transform-object-rest-spread"] } diff --git a/README.md b/README.md index 4c33f2d..eee85d1 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,7 @@ lodash.memoize x 3.941.183 fast-memoize x 34.699.858 memoize-state x 4.615.104 ``` +> this 4 millions operations per second? A bit more that enough ## The common memoization Memoize-state is not a best fit for a common case. It is designed to handle @@ -271,11 +272,37 @@ and numbers differs. ``` memoize-state is comparable with lodash and underscore, even in this example. +## Spread no-op +>memoize-state: object spread detected in XXX. Consider refactoring. + +Memoize state could not properly work if you "spread" state +```js +const mapStateToProps = ({prop,i,need,...rest}) =>.... +//or +const mapStateToProps = (state, props) => ({ ...state, ...props }) +//or +const mapState = ({ page, direction, ...state }) => ({ + page, + direction, + isLoading: isLoading(state) +}) +``` +It will assume, that you need ALL the keys, meanwhile - you could not. + +Workaround - refactor the code +```js +const mapState = state => ({ + page: state.page, + direction: state.direction, + isLoading: isLoading(state) +}) +``` + +See [issue](https://github.com/theKashey/memoize-state/issues/3#issuecomment-372226092) for more details ## Compatibility -__NOT__ compatible with __IE11__. One have to provide a proxy polyfill to make this work. -See https://github.com/GoogleChrome/proxy-polyfill +IE11/Android compatible. Contains [proxy-polyfill](https://github.com/GoogleChrome/proxy-polyfill) inside. # Licence MIT \ No newline at end of file diff --git a/_tests/smoke.spec.js b/_tests/smoke.spec.js index c958180..e8ab592 100644 --- a/_tests/smoke.spec.js +++ b/_tests/smoke.spec.js @@ -1,5 +1,6 @@ import {expect} from 'chai'; import {isProxyfied} from 'proxyequal'; +import sinon from 'sinon'; import memoize, {shouldBePure, isThisPure} from '../src/index'; describe('memoize-proxy', () => { @@ -394,6 +395,17 @@ describe('memoize-proxy', () => { expect(isThisPure(() => fun3(array))).to.be.true; }); + it('should report about spread operator', () => { + const mapState = ({a, ...rest}) => a; + const fn = memoize(mapState); + const spy = sinon.stub(console, "warn"); + fn({a: 1, b: 1}); + + sinon.assert.calledWith(spy, 'memoize-state: object spread detected in ', mapState, '. Consider refactoring.'); + + spy.restore(); + }); + describe('shouldBePure', () => { const A = [1, 2, 3]; diff --git a/lib/index.js b/lib/index.js index 3096adc..f824d56 100644 --- a/lib/index.js +++ b/lib/index.js @@ -257,7 +257,6 @@ function memoize(func) { return func.call.apply(func, [this].concat(args)); } - //let result = (options.shallowCheck && shallowHit(cache, args)) || (options.equalCheck && equalHit(cache, args)); var result = shallowEqualHit(cache, args); lastCallWasMemoized = Boolean(result); @@ -365,7 +364,7 @@ function memoize(func) { Object.defineProperty(functor, 'cacheStatistics', { get: function get() { return { - ratio: cacheHit / cacheHit, + ratio: cacheHit / cacheMiss, memoizationDisabled: memoizationDisabled, cacheHit: cacheHit, @@ -435,7 +434,7 @@ var shallowTest = function shallowTest(a, b) { } if (errors.length && errorMessage) { - console.error.call(console, errorMessage.map(function (err) { + console.error.apply(console, errorMessage.map(function (err) { return typeof err === 'string' ? err.replace('$KEYS$', errors.join(',')) : err; })); } @@ -466,7 +465,7 @@ var shallBePure = exports.shallBePure = function shallBePure(fnCall) { if (functor.isPure && lastResult) { if (lastResult !== fresult) { if (lastMemoizedResult === mresult) { - functor.isPure = shallowTest(lastResult, fresult, message + ' `' + fnCall.name + '`\'s result is not equal at [$KEYS$], while should be equal'); + functor.isPure = shallowTest(lastResult, fresult, message, fnCall, '`s result is not equal at [$KEYS$], while should be equal'); } } } diff --git a/package.json b/package.json index 3d49d63..b292e67 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "devDependencies": { "babel-cli": "^6.26.0", "babel-eslint": "^8.2.1", + "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-preset-env": "^1.6.1", "benchmark": "^2.1.4", "chai": "^4.1.2", @@ -45,6 +46,6 @@ }, "homepage": "https://github.com/theKashey/memoize-state#readme", "dependencies": { - "proxyequal": "^1.4.0" + "proxyequal": "^1.4.1" } } diff --git a/src/index.js b/src/index.js index c066fa9..4e2eec1 100644 --- a/src/index.js +++ b/src/index.js @@ -117,9 +117,11 @@ function callIn(that, cache, args, func, memoizationDepth, proxyMap = []) { }); const newArgs = args.map((arg, index) => proxies[index] ? proxies[index].state : arg); const preResult = func.call(that, ...newArgs); + let spreadDetected = false; const affected = proxies .map(proxy => { if (proxy) { + spreadDetected |= proxy.spreadDetected; const affected = proxy.affected || emptyArray; return { useAffected: [...affected], @@ -135,6 +137,13 @@ function callIn(that, cache, args, func, memoizationDepth, proxyMap = []) { } else { updateCacheLine(cache, 0, cacheLine); } + + if (spreadDetected) { + if (process.env.NODE_ENV !== 'production') { + console.warn('memoize-state: object spread detected in ', func, '. Consider refactoring.'); + } + } + return result; } @@ -223,7 +232,6 @@ function memoize(func, _options = {}) { return func.call(this, ...args); } - //let result = (options.shallowCheck && shallowHit(cache, args)) || (options.equalCheck && equalHit(cache, args)); let result = (shallowEqualHit(cache, args)); lastCallWasMemoized = Boolean(result); @@ -285,7 +293,7 @@ function memoize(func, _options = {}) { Object.defineProperty(functor, 'cacheStatistics', { get: () => ({ - ratio: cacheHit / cacheHit, + ratio: cacheHit / cacheMiss, memoizationDisabled, cacheHit, @@ -351,7 +359,7 @@ const shallowTest = (a, b, ...errorMessage) => { } if (errors.length && errorMessage) { - console.error.call(console, errorMessage.map(err => typeof err === 'string' ? err.replace('$KEYS$', errors.join(',')) : err)) + console.error.apply(console, errorMessage.map(err => typeof err === 'string' ? err.replace('$KEYS$', errors.join(',')) : err)) } return !errors.length; }; @@ -376,7 +384,7 @@ export const shallBePure = (fnCall, message = 'shouldBePure') => { if (functor.isPure && lastResult) { if (lastResult !== fresult) { if (lastMemoizedResult === mresult) { - functor.isPure = shallowTest(lastResult, fresult, message + ' `' + fnCall.name + '`\'s result is not equal at [$KEYS$], while should be equal'); + functor.isPure = shallowTest(lastResult, fresult, message, fnCall, '`s result is not equal at [$KEYS$], while should be equal'); } } } diff --git a/yarn.lock b/yarn.lock index 6dd5388..ef5a0a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -402,6 +402,10 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" @@ -590,6 +594,13 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" @@ -1944,9 +1955,9 @@ proxy-polyfill@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/proxy-polyfill/-/proxy-polyfill-0.2.0.tgz#3c9d2a0fe7682c3903674e304f5d27797b711446" -proxyequal@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/proxyequal/-/proxyequal-1.4.0.tgz#b613fd5c4adb8692627db38201a11e54fb211551" +proxyequal@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/proxyequal/-/proxyequal-1.4.1.tgz#8b1492aba54a3f54ebb3406c5df7b825ddf1545a" dependencies: proxy-polyfill "^0.2.0" search-trie "^1.0.0"