Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

immer

Package Overview
Dependencies
Maintainers
1
Versions
173
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

immer - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

8

changelog.md
# Changelog
### 1.3.0
* Improved the behavior of recursive producer calls. A producer that is called from another producer is now a no-op; that is, the draft will only be finalized once the outer-most producer completes. Pro and cons of this approach are discussed in [here](https://github.com/mweststrate/immer/issues/100#issuecomment-375216607). Fixes [#100](https://github.com/mweststrate/immer/issues/100)
* Immer no longer relies on `Object.assign` to be present / polyfilled. See[#139](https://github.com/mweststrate/immer/pull/139) by @celebro
* Improved some error messages, see [#144](https://github.com/mweststrate/immer/pull/144) by @btnwtn
### 1.2.1

@@ -57,3 +63,3 @@

* Added 'polyfill' for `Symbol`, fixes [#75](https://github.com/mweststrate/immer/issues/75)
* Added 'polyfill' for `Symbol`, fixes [#75](https://github.com/mweststrate/immer/issues/75)

@@ -60,0 +66,0 @@ ### 0.8.2

44

dist/immer.js

@@ -61,6 +61,15 @@ 'use strict';

var assign = Object.assign || function assign(target, value) {
for (var key in value) {
if (has(value, key)) {
target[key] = value[key];
}
}
return target;
};
function shallowCopy(value) {
if (Array.isArray(value)) return value.slice();
if (value.__proto__ === undefined) return Object.assign(Object.create(null), value);
return Object.assign({}, value);
var target = value.__proto__ === undefined ? Object.create(null) : {};
return assign(target, value);
}

@@ -151,3 +160,3 @@

setPrototypeOf: function setPrototypeOf() {
throw new Error("Don't even try this...");
throw new Error("Immer does not support `setPrototypeOf()`.");
}

@@ -219,3 +228,3 @@ };

function defineProperty$1() {
throw new Error("Immer does currently not support defining properties on draft objects");
throw new Error("Immer does not support defining properties on draft objects.");
}

@@ -235,2 +244,3 @@

function createProxy(parentState, base) {
if (isProxy(base)) throw new Error("Immer bug. Plz report.");
var state = createState(parentState, base);

@@ -243,2 +253,7 @@ var proxy = Array.isArray(base) ? Proxy.revocable([state], arrayTraps) : Proxy.revocable(state, objectTraps);

function produceProxy(baseState, producer) {
if (isProxy(baseState)) {
// See #100, don't nest producers
var returnValue = producer.call(baseState, baseState);
return returnValue === undefined ? baseState : returnValue;
}
var previousProxies = proxies;

@@ -250,7 +265,7 @@ proxies = [];

// execute the thunk
var returnValue = producer.call(rootProxy, rootProxy);
var _returnValue = producer.call(rootProxy, rootProxy);
// and finalize the modified proxy
var result = void 0;
// check whether the draft was modified and/or a value was returned
if (returnValue !== undefined && returnValue !== rootProxy) {
if (_returnValue !== undefined && _returnValue !== rootProxy) {
// something was returned, and it wasn't the proxy itself

@@ -262,3 +277,3 @@ if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR);

// Looks like a wrongly modeled reducer
result = finalize(returnValue);
result = finalize(_returnValue);
} else {

@@ -361,6 +376,6 @@ result = finalize(rootProxy);

function assertUnfinished(state) {
if (state.finished === true) throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process?");
if (state.finished === true) throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + JSON.stringify(state.copy || state.base));
}
// this sounds very expensive, but actually it is not that extensive in practice
// this sounds very expensive, but actually it is not that expensive in practice
// as it will only visit proxies, and only do key-based change detection for objects for

@@ -407,2 +422,7 @@ // which it is not already know that they are changed (that is, only object for which no known key was changed)

function produceEs5(baseState, producer) {
if (isProxy(baseState)) {
// See #100, don't nest producers
var returnValue = producer.call(baseState, baseState);
return returnValue === undefined ? baseState : returnValue;
}
var prevStates = states;

@@ -414,3 +434,3 @@ states = [];

// execute the thunk
var returnValue = producer.call(rootProxy, rootProxy);
var _returnValue = producer.call(rootProxy, rootProxy);
// and finalize the modified proxy

@@ -425,6 +445,6 @@ each(states, function (_, state) {

// check whether the draft was modified and/or a value was returned
if (returnValue !== undefined && returnValue !== rootProxy) {
if (_returnValue !== undefined && _returnValue !== rootProxy) {
// something was returned, and it wasn't the proxy itself
if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR);
result = finalize(returnValue);
result = finalize(_returnValue);
} else result = finalize(rootProxy);

@@ -431,0 +451,0 @@ // make sure all proxies become unusable

@@ -57,6 +57,15 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {

var assign = Object.assign || function assign(target, value) {
for (var key in value) {
if (has(value, key)) {
target[key] = value[key];
}
}
return target;
};
function shallowCopy(value) {
if (Array.isArray(value)) return value.slice();
if (value.__proto__ === undefined) return Object.assign(Object.create(null), value);
return Object.assign({}, value);
var target = value.__proto__ === undefined ? Object.create(null) : {};
return assign(target, value);
}

@@ -147,3 +156,3 @@

setPrototypeOf: function setPrototypeOf() {
throw new Error("Don't even try this...");
throw new Error("Immer does not support `setPrototypeOf()`.");
}

@@ -215,3 +224,3 @@ };

function defineProperty$1() {
throw new Error("Immer does currently not support defining properties on draft objects");
throw new Error("Immer does not support defining properties on draft objects.");
}

@@ -231,2 +240,3 @@

function createProxy(parentState, base) {
if (isProxy(base)) throw new Error("Immer bug. Plz report.");
var state = createState(parentState, base);

@@ -239,2 +249,7 @@ var proxy = Array.isArray(base) ? Proxy.revocable([state], arrayTraps) : Proxy.revocable(state, objectTraps);

function produceProxy(baseState, producer) {
if (isProxy(baseState)) {
// See #100, don't nest producers
var returnValue = producer.call(baseState, baseState);
return returnValue === undefined ? baseState : returnValue;
}
var previousProxies = proxies;

@@ -246,7 +261,7 @@ proxies = [];

// execute the thunk
var returnValue = producer.call(rootProxy, rootProxy);
var _returnValue = producer.call(rootProxy, rootProxy);
// and finalize the modified proxy
var result = void 0;
// check whether the draft was modified and/or a value was returned
if (returnValue !== undefined && returnValue !== rootProxy) {
if (_returnValue !== undefined && _returnValue !== rootProxy) {
// something was returned, and it wasn't the proxy itself

@@ -258,3 +273,3 @@ if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR);

// Looks like a wrongly modeled reducer
result = finalize(returnValue);
result = finalize(_returnValue);
} else {

@@ -357,6 +372,6 @@ result = finalize(rootProxy);

function assertUnfinished(state) {
if (state.finished === true) throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process?");
if (state.finished === true) throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + JSON.stringify(state.copy || state.base));
}
// this sounds very expensive, but actually it is not that extensive in practice
// this sounds very expensive, but actually it is not that expensive in practice
// as it will only visit proxies, and only do key-based change detection for objects for

@@ -403,2 +418,7 @@ // which it is not already know that they are changed (that is, only object for which no known key was changed)

function produceEs5(baseState, producer) {
if (isProxy(baseState)) {
// See #100, don't nest producers
var returnValue = producer.call(baseState, baseState);
return returnValue === undefined ? baseState : returnValue;
}
var prevStates = states;

@@ -410,3 +430,3 @@ states = [];

// execute the thunk
var returnValue = producer.call(rootProxy, rootProxy);
var _returnValue = producer.call(rootProxy, rootProxy);
// and finalize the modified proxy

@@ -421,6 +441,6 @@ each(states, function (_, state) {

// check whether the draft was modified and/or a value was returned
if (returnValue !== undefined && returnValue !== rootProxy) {
if (_returnValue !== undefined && _returnValue !== rootProxy) {
// something was returned, and it wasn't the proxy itself
if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR);
result = finalize(returnValue);
result = finalize(_returnValue);
} else result = finalize(rootProxy);

@@ -427,0 +447,0 @@ // make sure all proxies become unusable

@@ -1,2 +0,2 @@

var e,r;e=this,r=function(e){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n="undefined"!=typeof Symbol?Symbol("immer-proxy-state"):"__$immer_state",t="An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.";var o=!("undefined"!=typeof process&&"production"===process.env.NODE_ENV||"verifyMinified"!==function(){}.name),i="undefined"!=typeof Proxy;function f(e){return!!e&&!!e[n]}function u(e){if(!e)return!1;if("object"!==(void 0===e?"undefined":r(e)))return!1;if(Array.isArray(e))return!0;var n=Object.getPrototypeOf(e);return null===n||n===Object.prototype}function a(e){return o&&Object.freeze(e),e}function c(e){return Array.isArray(e)?e.slice():void 0===e.__proto__?Object.assign(Object.create(null),e):Object.assign({},e)}function s(e,r){if(Array.isArray(e))for(var n=0;n<e.length;n++)r(n,e[n]);else for(var t in e)r(t,e[t])}function d(e,r){return Object.prototype.hasOwnProperty.call(e,r)}function p(e){if(f(e)){var r=e[n];return!0===r.modified?!0===r.finalized?r.copy:(r.finalized=!0,t=i?r.copy:r.copy=c(e),o=r.base,s(t,function(e,r){r!==o[e]&&(t[e]=p(r))}),a(t)):r.base}var t,o;return function e(r){if(!u(r))return;if(Object.isFrozen(r))return;s(r,function(n,t){f(t)?r[n]=p(t):e(t)});a(r)}(e),e}function y(e,r){return e===r?0!==e||1/e==1/r:e!=e&&r!=r}var l=null,b={get:function(e,r){if(r===n)return e;if(e.modified){var t=e.copy[r];return t===e.base[r]&&u(t)?e.copy[r]=g(e,t):t}if(d(e.proxies,r))return e.proxies[r];var o=e.base[r];return!f(o)&&u(o)?e.proxies[r]=g(e,o):o},has:function(e,r){return r in m(e)},ownKeys:function(e){return Reflect.ownKeys(m(e))},set:function(e,r,n){if(!e.modified){if(r in e.base&&y(e.base[r],n)||d(e.proxies,r)&&e.proxies[r]===n)return!0;h(e)}return e.copy[r]=n,!0},deleteProperty:function(e,r){return h(e),delete e.copy[r],!0},getOwnPropertyDescriptor:function(e,r){var n=e.modified?e.copy:d(e.proxies,r)?e.proxies:e.base,t=Reflect.getOwnPropertyDescriptor(n,r);!t||Array.isArray(n)&&"length"===r||(t.configurable=!0);return t},defineProperty:function(){throw new Error("Immer does currently not support defining properties on draft objects")},setPrototypeOf:function(){throw new Error("Don't even try this...")}},v={};function m(e){return!0===e.modified?e.copy:e.base}function h(e){e.modified||(e.modified=!0,e.copy=c(e.base),Object.assign(e.copy,e.proxies),e.parent&&h(e.parent))}function g(e,r){var n={modified:!1,finalized:!1,parent:e,base:r,copy:void 0,proxies:{}},t=Array.isArray(r)?Proxy.revocable([n],v):Proxy.revocable(n,b);return l.push(t),t.proxy}s(b,function(e,r){v[e]=function(){return arguments[0]=arguments[0][0],r.apply(this,arguments)}});var w={},j=null;function O(e){return e.hasCopy?e.copy:e.base}function x(e){e.modified||(e.modified=!0,e.parent&&x(e.parent))}function P(e){e.hasCopy||(e.hasCopy=!0,e.copy=c(e.base))}function A(e,r){var t=c(r);s(r,function(e){var r;Object.defineProperty(t,""+e,w[r=""+e]||(w[r]={configurable:!0,enumerable:!0,get:function(){return function(e,r){E(e);var n=O(e)[r];return!e.finalizing&&n===e.base[r]&&u(n)?(P(e),e.copy[r]=A(e,n)):n}(this[n],r)},set:function(e){!function(e,r,n){if(E(e),!e.modified){if(y(O(e)[r],n))return;x(e),P(e)}e.copy[r]=n}(this[n],r,e)}}))});var o,i,f,a={modified:!1,hasCopy:!1,parent:e,base:r,proxy:t,copy:void 0,finished:!1,finalizing:!1,finalized:!1};return o=t,i=n,f=a,Object.defineProperty(o,i,{value:f,enumerable:!1,writable:!0}),j.push(a),t}function E(e){if(!0===e.finished)throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process?")}function z(e){var r=e.proxy;if(r.length!==e.base.length)return!0;var n=Object.getOwnPropertyDescriptor(r,r.length-1);return!(!n||n.get)}function _(e,o){var i=j;j=[];try{var f=A(void 0,e),u=o.call(f,f);s(j,function(e,r){r.finalizing=!0}),function(){for(var e=j.length-1;e>=0;e--){var n=j[e];!1===n.modified&&(Array.isArray(n.base)?z(n)&&x(n):(t=n,o=Object.keys(t.base),i=Object.keys(t.proxy),function(e,n){if(y(e,n))return!0;if("object"!==(void 0===e?"undefined":r(e))||null===e||"object"!==(void 0===n?"undefined":r(n))||null===n)return!1;var t=Object.keys(e),o=Object.keys(n);if(t.length!==o.length)return!1;for(var i=0;i<t.length;i++)if(!hasOwnProperty.call(n,t[i])||!y(e[t[i]],n[t[i]]))return!1;return!0}(o,i)||x(n)))}var t,o,i}();var a=void 0;if(void 0!==u&&u!==f){if(f[n].modified)throw new Error(t);a=p(u)}else a=p(f);return s(j,function(e,r){r.finished=!0}),a}finally{j=i}}e.default=function e(o,f){if(1!==arguments.length&&2!==arguments.length)throw new Error("produce expects 1 or 2 arguments, got "+arguments.length);if("function"==typeof o){if("function"==typeof f)throw new Error("if first argument is a function (curried invocation), the second argument to produce cannot be a function");var a=f,c=o;return function(){var r=arguments;return e(void 0===r[0]&&void 0!==a?a:r[0],function(e){return r[0]=e,c.apply(e,r)})}}if("function"!=typeof f)throw new Error("if first argument is not a function, the second argument to produce should be a function");if("object"!==(void 0===o?"undefined":r(o))||null===o)return f(o);if(!u(o))throw new Error("the first argument to an immer producer should be a primitive, plain object or array, got "+(void 0===o?"undefined":r(o))+': "'+o+'"');return i?function(e,r){var o=l;l=[];try{var i=g(void 0,e),f=r.call(i,i),u=void 0;if(void 0!==f&&f!==i){if(i[n].modified)throw new Error(t);u=p(f)}else u=p(i);return s(l,function(e,r){return r.revoke()}),u}finally{l=o}}(o,f):_(o,f)},e.setAutoFreeze=function(e){o=e},e.setUseProxies=function(e){i=e},Object.defineProperty(e,"__esModule",{value:!0})},"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r(e.immer={});
var e,r;e=this,r=function(e){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n="undefined"!=typeof Symbol?Symbol("immer-proxy-state"):"__$immer_state",t="An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.";var o=!("undefined"!=typeof process&&"production"===process.env.NODE_ENV||"verifyMinified"!==function(){}.name),i="undefined"!=typeof Proxy;function f(e){return!!e&&!!e[n]}function u(e){if(!e)return!1;if("object"!==(void 0===e?"undefined":r(e)))return!1;if(Array.isArray(e))return!0;var n=Object.getPrototypeOf(e);return null===n||n===Object.prototype}function a(e){return o&&Object.freeze(e),e}var c=Object.assign||function(e,r){for(var n in r)p(r,n)&&(e[n]=r[n]);return e};function s(e){if(Array.isArray(e))return e.slice();var r=void 0===e.__proto__?Object.create(null):{};return c(r,e)}function d(e,r){if(Array.isArray(e))for(var n=0;n<e.length;n++)r(n,e[n]);else for(var t in e)r(t,e[t])}function p(e,r){return Object.prototype.hasOwnProperty.call(e,r)}function y(e){if(f(e)){var r=e[n];return!0===r.modified?!0===r.finalized?r.copy:(r.finalized=!0,t=i?r.copy:r.copy=s(e),o=r.base,d(t,function(e,r){r!==o[e]&&(t[e]=y(r))}),a(t)):r.base}var t,o;return function e(r){if(!u(r))return;if(Object.isFrozen(r))return;d(r,function(n,t){f(t)?r[n]=y(t):e(t)});a(r)}(e),e}function l(e,r){return e===r?0!==e||1/e==1/r:e!=e&&r!=r}var v=null,b={get:function(e,r){if(r===n)return e;if(e.modified){var t=e.copy[r];return t===e.base[r]&&u(t)?e.copy[r]=w(e,t):t}if(p(e.proxies,r))return e.proxies[r];var o=e.base[r];return!f(o)&&u(o)?e.proxies[r]=w(e,o):o},has:function(e,r){return r in h(e)},ownKeys:function(e){return Reflect.ownKeys(h(e))},set:function(e,r,n){if(!e.modified){if(r in e.base&&l(e.base[r],n)||p(e.proxies,r)&&e.proxies[r]===n)return!0;g(e)}return e.copy[r]=n,!0},deleteProperty:function(e,r){return g(e),delete e.copy[r],!0},getOwnPropertyDescriptor:function(e,r){var n=e.modified?e.copy:p(e.proxies,r)?e.proxies:e.base,t=Reflect.getOwnPropertyDescriptor(n,r);!t||Array.isArray(n)&&"length"===r||(t.configurable=!0);return t},defineProperty:function(){throw new Error("Immer does not support defining properties on draft objects.")},setPrototypeOf:function(){throw new Error("Immer does not support `setPrototypeOf()`.")}},m={};function h(e){return!0===e.modified?e.copy:e.base}function g(e){e.modified||(e.modified=!0,e.copy=s(e.base),Object.assign(e.copy,e.proxies),e.parent&&g(e.parent))}function w(e,r){if(f(r))throw new Error("Immer bug. Plz report.");var n={modified:!1,finalized:!1,parent:e,base:r,copy:void 0,proxies:{}},t=Array.isArray(r)?Proxy.revocable([n],m):Proxy.revocable(n,b);return v.push(t),t.proxy}d(b,function(e,r){m[e]=function(){return arguments[0]=arguments[0][0],r.apply(this,arguments)}});var O={},j=null;function x(e){return e.hasCopy?e.copy:e.base}function P(e){e.modified||(e.modified=!0,e.parent&&P(e.parent))}function A(e){e.hasCopy||(e.hasCopy=!0,e.copy=s(e.base))}function E(e,r){var t=s(r);d(r,function(e){var r;Object.defineProperty(t,""+e,O[r=""+e]||(O[r]={configurable:!0,enumerable:!0,get:function(){return function(e,r){z(e);var n=x(e)[r];return!e.finalizing&&n===e.base[r]&&u(n)?(A(e),e.copy[r]=E(e,n)):n}(this[n],r)},set:function(e){!function(e,r,n){if(z(e),!e.modified){if(l(x(e)[r],n))return;P(e),A(e)}e.copy[r]=n}(this[n],r,e)}}))});var o,i,f,a={modified:!1,hasCopy:!1,parent:e,base:r,proxy:t,copy:void 0,finished:!1,finalizing:!1,finalized:!1};return o=t,i=n,f=a,Object.defineProperty(o,i,{value:f,enumerable:!1,writable:!0}),j.push(a),t}function z(e){if(!0===e.finished)throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? "+JSON.stringify(e.copy||e.base))}function _(e){var r=e.proxy;if(r.length!==e.base.length)return!0;var n=Object.getOwnPropertyDescriptor(r,r.length-1);return!(!n||n.get)}function S(e,o){if(f(e)){var i=o.call(e,e);return void 0===i?e:i}var u=j;j=[];try{var a=E(void 0,e),c=o.call(a,a);d(j,function(e,r){r.finalizing=!0}),function(){for(var e=j.length-1;e>=0;e--){var n=j[e];!1===n.modified&&(Array.isArray(n.base)?_(n)&&P(n):(t=n,o=Object.keys(t.base),i=Object.keys(t.proxy),function(e,n){if(l(e,n))return!0;if("object"!==(void 0===e?"undefined":r(e))||null===e||"object"!==(void 0===n?"undefined":r(n))||null===n)return!1;var t=Object.keys(e),o=Object.keys(n);if(t.length!==o.length)return!1;for(var i=0;i<t.length;i++)if(!hasOwnProperty.call(n,t[i])||!l(e[t[i]],n[t[i]]))return!1;return!0}(o,i)||P(n)))}var t,o,i}();var s=void 0;if(void 0!==c&&c!==a){if(a[n].modified)throw new Error(t);s=y(c)}else s=y(a);return d(j,function(e,r){r.finished=!0}),s}finally{j=u}}e.default=function e(o,a){if(1!==arguments.length&&2!==arguments.length)throw new Error("produce expects 1 or 2 arguments, got "+arguments.length);if("function"==typeof o){if("function"==typeof a)throw new Error("if first argument is a function (curried invocation), the second argument to produce cannot be a function");var c=a,s=o;return function(){var r=arguments;return e(void 0===r[0]&&void 0!==c?c:r[0],function(e){return r[0]=e,s.apply(e,r)})}}if("function"!=typeof a)throw new Error("if first argument is not a function, the second argument to produce should be a function");if("object"!==(void 0===o?"undefined":r(o))||null===o)return a(o);if(!u(o))throw new Error("the first argument to an immer producer should be a primitive, plain object or array, got "+(void 0===o?"undefined":r(o))+': "'+o+'"');return i?function(e,r){if(f(e)){var o=r.call(e,e);return void 0===o?e:o}var i=v;v=[];try{var u=w(void 0,e),a=r.call(u,u),c=void 0;if(void 0!==a&&a!==u){if(u[n].modified)throw new Error(t);c=y(a)}else c=y(u);return d(v,function(e,r){return r.revoke()}),c}finally{v=i}}(o,a):S(o,a)},e.setAutoFreeze=function(e){o=e},e.setUseProxies=function(e){i=e},Object.defineProperty(e,"__esModule",{value:!0})},"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r(e.immer={});
//# sourceMappingURL=immer.umd.js.map
{
"name": "immer",
"version": "1.2.1",
"version": "1.3.0",
"description": "Create your next immutable state by mutating the current one",

@@ -12,2 +12,3 @@ "main": "dist/immer.js",

"scripts": {
"watch": "jest --watch",
"test": "jest",

@@ -14,0 +15,0 @@ "test:perf": "yarn-or-npm build && node --expose-gc node_modules/jest-cli/bin/jest.js --verbose --testRegex '__performance_tests__/.*?js$'",

# Immer
[![npm](https://img.shields.io/npm/v/immer.svg)](https://www.npmjs.com/package/immer)
[![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/immer/dist/immer.umd.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/immer/dist/immer.umd.js)
[![Build Status](https://travis-ci.org/mweststrate/immer.svg?branch=master)](https://travis-ci.org/mweststrate/immer)
[![Coverage Status](https://coveralls.io/repos/github/mweststrate/immer/badge.svg?branch=master)](https://coveralls.io/github/mweststrate/immer?branch=master)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/michelweststrate)
[![npm](https://img.shields.io/npm/v/immer.svg)](https://www.npmjs.com/package/immer) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/immer/dist/immer.umd.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/immer/dist/immer.umd.js) [![Build Status](https://travis-ci.org/mweststrate/immer.svg?branch=master)](https://travis-ci.org/mweststrate/immer) [![Coverage Status](https://coveralls.io/repos/github/mweststrate/immer/badge.svg?branch=master)](https://coveralls.io/github/mweststrate/immer?branch=master) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/michelweststrate)

@@ -17,4 +12,4 @@ _Create the next immutable state tree by simply modifying the current tree_

* CDN: Exposed global is `immer`
* Unpkg: `<script src="https://unpkg.com/immer/dist/immer.umd.js"></script>`
* JSDelivr: `<script src="https://cdn.jsdelivr.net/npm/immer/dist/immer.umd.js"></script>`
* Unpkg: `<script src="https://unpkg.com/immer/dist/immer.umd.js"></script>`
* JSDelivr: `<script src="https://cdn.jsdelivr.net/npm/immer/dist/immer.umd.js"></script>`

@@ -26,8 +21,5 @@ ---

Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
It is based on the [_copy-on-write_](https://en.wikipedia.org/wiki/Copy-on-write) mechanism.
Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way. It is based on the [_copy-on-write_](https://en.wikipedia.org/wiki/Copy-on-write) mechanism.
The basic idea is that you will apply all your changes to a temporarily _draftState_, which is a proxy of the _currentState_.
Once all your mutations are completed, Immer will produce the _nextState_ based on the mutations to the draft state.
This means that you can interact with your data by simply modifying it, while keeping all the benefits of immutable data.
The basic idea is that you will apply all your changes to a temporarily _draftState_, which is a proxy of the _currentState_. Once all your mutations are completed, Immer will produce the _nextState_ based on the mutations to the draft state. This means that you can interact with your data by simply modifying it, while keeping all the benefits of immutable data.

@@ -65,3 +57,3 @@ ![immer-hd.png](images/hd/immer.png)

const nextState = produce(baseState, draftState => {
draftState.push({ todo: "Tweet about it" })
draftState.push({todo: "Tweet about it"})
draftState[1].done = true

@@ -109,14 +101,14 @@ })

const byId = (state, action) => {
switch (action.type) {
case RECEIVE_PRODUCTS:
return {
...state,
...action.products.reduce((obj, product) => {
obj[product.id] = product
return obj
}, {})
}
default:
return state
}
switch (action.type) {
case RECEIVE_PRODUCTS:
return {
...state,
...action.products.reduce((obj, product) => {
obj[product.id] = product
return obj
}, {})
}
default:
return state
}
}

@@ -128,13 +120,13 @@ ```

```javascript
import produce from 'immer'
import produce from "immer"
const byId = (state, action) =>
produce(state, draft => {
switch (action.type) {
case RECEIVE_PRODUCTS:
action.products.forEach(product => {
draft[product.id] = product
})
}
})
produce(state, draft => {
switch (action.type) {
case RECEIVE_PRODUCTS:
action.products.forEach(product => {
draft[product.id] = product
})
}
})
```

@@ -144,5 +136,3 @@

Creating Redux reducer is just a sample application of the Immer package.
Immer is not just designed to simplify Redux reducers.
It can be used in any context where you have an immutable data tree that you want to clone and modify (with structural sharing).
Creating Redux reducer is just a sample application of the Immer package. Immer is not just designed to simplify Redux reducers. It can be used in any context where you have an immutable data tree that you want to clone and modify (with structural sharing).

@@ -153,4 +143,3 @@ _Note: it might be tempting after using producers for a while, to just place `produce` in your root reducer and then pass the draft to each reducer and work directly over such draft. Don't do that. It kills the point of Redux where each reducer is testable as pure reducer. Immer is best used when applying it to small individual pieces of logic._

Deep updates in the state of React components can be greatly simplified as well by using immer.
Take for example the following onClick handlers (Try in [codesandbox](https://codesandbox.io/s/m4yp57632j)):
Deep updates in the state of React components can be greatly simplified as well by using immer. Take for example the following onClick handlers (Try in [codesandbox](https://codesandbox.io/s/m4yp57632j)):

@@ -162,3 +151,3 @@ ```javascript

onBirthDayClick1 = () => {
this.setState((prevState)=>({
this.setState(prevState => ({
user: {

@@ -174,7 +163,9 @@ ...prevState.user,

* we can just create a curried producer and further simplify!
*/
*/
onBirthDayClick2 = () => {
this.setState(produce(draft => {
draft.user.age += 1
}))
this.setState(
produce(draft => {
draft.user.age += 1
})
)
}

@@ -185,4 +176,3 @@ ```

Passing a function as the first argument to `produce` is intended to be used for currying. This means that you get a pre-bound producer that only needs a state to produce the value from.
The producer function gets passed in the draft, and any further arguments that were passed to the curried function.
Passing a function as the first argument to `produce` is intended to be used for currying. This means that you get a pre-bound producer that only needs a state to produce the value from. The producer function gets passed in the draft, and any further arguments that were passed to the curried function.

@@ -224,17 +214,17 @@ For example:

```javascript
import produce from 'immer'
import produce from "immer"
const byId = produce(
(draft, action) => {
switch (action.type) {
case RECEIVE_PRODUCTS:
action.products.forEach(product => {
draft[product.id] = product
})
return
(draft, action) => {
switch (action.type) {
case RECEIVE_PRODUCTS:
action.products.forEach(product => {
draft[product.id] = product
})
return
}
},
{
1: {id: 1, name: "product-1"}
}
},
{
1: { id: 1, name: "product-1" }
}
)

@@ -245,49 +235,42 @@ ```

Immer automatically freezes any state trees that are modified using `produce`.
This protects against accidental modifications of the state tree outside of a producer.
This comes with a performance impact, so it is recommended to disable this option in production.
It is by default enabled.
By default it is turned on during local development, and turned off in production.
Use `setAutoFreeze(true / false)` to explicitly turn this feature on or off.
Immer automatically freezes any state trees that are modified using `produce`. This protects against accidental modifications of the state tree outside of a producer. This comes with a performance impact, so it is recommended to disable this option in production. It is by default enabled. By default it is turned on during local development, and turned off in production. Use `setAutoFreeze(true / false)` to explicitly turn this feature on or off.
## Returning data from producers
It is not needed to return anything from a producer, as Immer will return the (finalized) version of the `draft` anyway.
However, it is allowed to just `return draft`.
It is not needed to return anything from a producer, as Immer will return the (finalized) version of the `draft` anyway. However, it is allowed to just `return draft`.
It is also allowed to return arbitrarily other data from the producer function. But _only_ if you didn't modify the draft.
This can be useful to produce an entirely new state. Some examples:
It is also allowed to return arbitrarily other data from the producer function. But _only_ if you didn't modify the draft. This can be useful to produce an entirely new state. Some examples:
```javascript
const userReducer = produce((draft, action) => {
switch (action.type) {
case "renameUser":
// OK: we modify the current state
draft.users[action.payload.id].name = action.payload.name
return draft // same as just 'return'
case "loadUsers":
// OK: we return an entirely new state
return action.payload
case "adduser-1":
// NOT OK: This doesn't do change the draft nor return a new state!
// It doesn't modify the draft (it just redeclares it)
// In fact, this just doesn't do anything at all
draft = { users: [...draft.users, action.payload]}
return
case "adduser-2":
// NOT OK: modifying draft *and* returning a new state
draft.userCount += 1
return { users: [...draft.users, action.payload] }
case "adduser-3":
// OK: returning a new state. But, unnecessary complex and expensive
return {
userCount: draft.userCount + 1,
users: [...draft.users, action.payload]
}
case "adduser-4":
// OK: the immer way
draft.userCount += 1
draft.push(action.payload)
return
}
switch (action.type) {
case "renameUser":
// OK: we modify the current state
draft.users[action.payload.id].name = action.payload.name
return draft // same as just 'return'
case "loadUsers":
// OK: we return an entirely new state
return action.payload
case "adduser-1":
// NOT OK: This doesn't do change the draft nor return a new state!
// It doesn't modify the draft (it just redeclares it)
// In fact, this just doesn't do anything at all
draft = {users: [...draft.users, action.payload]}
return
case "adduser-2":
// NOT OK: modifying draft *and* returning a new state
draft.userCount += 1
return {users: [...draft.users, action.payload]}
case "adduser-3":
// OK: returning a new state. But, unnecessary complex and expensive
return {
userCount: draft.userCount + 1,
users: [...draft.users, action.payload]
}
case "adduser-4":
// OK: the immer way
draft.userCount += 1
draft.users.push(action.payload)
return
}
})

@@ -303,6 +286,6 @@ ```

```javascript
const base = { counter: 0 }
const base = {counter: 0}
const next = produce(base, function() {
this.counter++
this.counter++
})

@@ -313,3 +296,3 @@ console.log(next.counter) // 1

const increment = produce(function() {
this.counter++
this.counter++
})

@@ -325,6 +308,3 @@ console.log(increment(base).counter) // 1

By default `produce` tries to use proxies for optimal performance.
However, on older JavaScript engines `Proxy` is not available.
For example, when running Microsoft Internet Explorer or React Native on Android.
In such cases Immer will fallback to an ES5 compatible implementation which works identical, but is a bit slower.
By default `produce` tries to use proxies for optimal performance. However, on older JavaScript engines `Proxy` is not available. For example, when running Microsoft Internet Explorer or React Native on Android. In such cases Immer will fallback to an ES5 compatible implementation which works identical, but is a bit slower.

@@ -335,6 +315,6 @@ ## Pitfalls

1. Currently, Immer only supports plain objects and arrays. PRs are welcome for more language built-in types like `Map` and `Set`.
2. Immer only processes native arrays and plain objects (with a prototype of `null` or `Object`). Any other type of value will be treated verbatim! So if you modify a `Map` or `Buffer` (or whatever complex object from the draft state), the changes will be persisted. But, both in your new and old state! So, in such cases, make sure to always produce fresh instances if you want to keep your state truly immutable.
3. For example, working with `Date` objects is no problem, just make sure you never modify them (by using methods like `setYear` on an existing instance). Instead, always create fresh `Date` instances. Which is probably what you were unconsciously doing already.
4. Since Immer uses proxies, reading huge amounts of data from state comes with an overhead (especially in the ES5 implementation). If this ever becomes an issue (measure before you optimize!), do the current state analysis before entering the producer function or read from the `currentState` rather than the `draftState`
5. Some debuggers (at least Node 6 is known) have trouble debugging when Proxies are in play. Node 8 is known to work correctly.
1. Immer only processes native arrays and plain objects (with a prototype of `null` or `Object`). Any other type of value will be treated verbatim! So if you modify a `Map` or `Buffer` (or whatever complex object from the draft state), the changes will be persisted. But, both in your new and old state! So, in such cases, make sure to always produce fresh instances if you want to keep your state truly immutable.
1. For example, working with `Date` objects is no problem, just make sure you never modify them (by using methods like `setYear` on an existing instance). Instead, always create fresh `Date` instances. Which is probably what you were unconsciously doing already.
1. Since Immer uses proxies, reading huge amounts of data from state comes with an overhead (especially in the ES5 implementation). If this ever becomes an issue (measure before you optimize!), do the current state analysis before entering the producer function or read from the `currentState` rather than the `draftState`
1. Some debuggers (at least Node 6 is known) have trouble debugging when Proxies are in play. Node 8 is known to work correctly.

@@ -347,2 +327,3 @@ ## Cool things built with immer

* [quick-redux](https://github.com/jeffreyyoung/quick-redux) _tools to make redux developement quicker and easier_
* [react-copy-write](https://github.com/aweary/react-copy-write) _Immutable state with a mutable API_

@@ -358,47 +339,47 @@ ## How does Immer work?

```javascript
import produce from "immer";
import produce from "immer"
// object mutations
const todosObj = {
id1: { done: false, body: "Take out the trash" },
id2: { done: false, body: "Check Email" }
};
id1: {done: false, body: "Take out the trash"},
id2: {done: false, body: "Check Email"}
}
// add
const addedTodosObj = produce(todosObj, draft => {
draft["id3"] = { done: false, body: "Buy bananas" };
});
draft["id3"] = {done: false, body: "Buy bananas"}
})
// delete
const deletedTodosObj = produce(todosObj, draft => {
delete draft["id1"];
});
delete draft["id1"]
})
// update
const updatedTodosObj = produce(todosObj, draft => {
draft["id1"].done = true;
});
draft["id1"].done = true
})
// array mutations
const todosArray = [
{ id: "id1", done: false, body: "Take out the trash" },
{ id: "id2", done: false, body: "Check Email" }
];
{id: "id1", done: false, body: "Take out the trash"},
{id: "id2", done: false, body: "Check Email"}
]
// add
const addedTodosArray = produce(todosArray, draft => {
draft.push({ id: "id3", done: false, body: "Buy bananas" });
});
draft.push({id: "id3", done: false, body: "Buy bananas"})
})
// delete
const deletedTodosArray = produce(todosArray, draft => {
draft.splice(draft.findIndex(todo => todo.id === "id1"), 1);
// or (slower):
// return draft.filter(todo => todo.id !== "id1")
});
draft.splice(draft.findIndex(todo => todo.id === "id1"), 1)
// or (slower):
// return draft.filter(todo => todo.id !== "id1")
})
// update
const updatedTodosArray = produce(todosArray, draft => {
draft[draft.findIndex(todo => todo.id === "id1")].done = true;
});
draft[draft.findIndex(todo => todo.id === "id1")].done = true
})
```

@@ -408,8 +389,5 @@

Here is a [simple benchmark](__performance_tests__/todo.js) on the performance of Immer.
This test takes 100.000 todo items, and updates 10.000 of them.
_Freeze_ indicates that the state tree has been frozen after producing it. This is a _development_ best practice, as it prevents developers from accidentally modifying the state tree.
Here is a [simple benchmark](__performance_tests__/todo.js) on the performance of Immer. This test takes 100.000 todo items, and updates 10.000 of them. _Freeze_ indicates that the state tree has been frozen after producing it. This is a _development_ best practice, as it prevents developers from accidentally modifying the state tree.
These tests were executed on Node 8.4.0.
Use `yarn test:perf` to reproduce them locally.
These tests were executed on Node 8.4.0. Use `yarn test:perf` to reproduce them locally.

@@ -419,2 +397,3 @@ ![performance.png](images/performance.png)

Some observations:
* From `immer` perspective, this benchmark is a _worst case_ scenario, because the root collection it has to proxy is really large relatively to the rest of the data set.

@@ -421,0 +400,0 @@ * The _mutate_, and _deepclone, mutate_ benchmarks establish a baseline on how expensive changing the data is, without immutability (or structural sharing in the deep clone case).

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc