immhelper
Fast and lightweight library helps you to update js objects without mutating them
Install with npm
npm install immhelper --save
Features
- Extreme fast
- Lightweight
- Provide many powerful mutating actions
- Easy to define custom mutating actions
- Support batch processing per spec
- Support pipe processing per spec
- Support deep updating with target path
- Support sub spec with filter
- Support named mutating actions
- Support typescripts auto complete
- Support proxy for selecting and updating target
- Support low level API to update spec for special cases
- Support conditional update actions: if, unless, switch
Playground
https://p5243pkx6q.codesandbox.io/
Change Logs:
1.0.35: Improve performance. Become fastest package for copying immutable objects.
Benchmarks (Fastest to Slowest)
Normal
immhelper: Total elapsed = 72 ms (read) + 2344 ms (write) = 2416 ms
Object.assign: Total elapsed = 104 ms (read) + 2394 ms (write) = 2498 ms
immutable-assign: Total elapsed = 82 ms (read) + 3814 ms (write) = 3896 ms
immer: Total elapsed = 74 ms (read) + 7490 ms (write) = 7564 ms
seamless-immutable: Total elapsed = 103 ms (read) + 60833 ms (write) = 60936 ms
immutability-helper: Total elapsed = 84 ms (read) + 65249 ms (write) = 65333 ms
update-immutable: Total elapsed = 88 ms (read) + 71726 ms (write) = 71814 ms
With Deep Freeze
Object.assign: Total elapsed = 107 ms (read) + 30407 ms (write) = 30514 ms
immhelper: Total elapsed = 96 ms (read) + 33167 ms (write) = 33263 ms
immer: Total elapsed = 103 ms (read) + 39337 ms (write) = 39440 ms
immutable-assign: Total elapsed = 102 ms (read) + 46764 ms (write) = 46866 ms
immutability-helper: Total elapsed = 104 ms (read) + 105779 ms (write) = 105883 ms
update-immutable: Total elapsed = 108 ms (read) + 107985 ms (write) = 108093 ms
Summary
1.03x Faster than Object.assign
1.61x Faster than immutable-assign
3.13x Faster than immer
25.22x Faster than seamless-immutable
27.04x Faster than immutability-helper
29.72x Faster than update-immutable
Samples
; const original = a: b: c: d: e: f: {} arrayPush: objMerge: name: "Peter" toggleMe: false toggleMyProp: done: false completed: true removeSecond: 1 2 3 4 removeAppleAndBanana: "Orange" "Apple" "Banana" unsetMyProp: data1: data2: true sqrt: 100 doubleItems: 1 2 3 4 5 6 7 8 swapItems: "left" "right" increaseProps: one: 1 two: 2 three: 3 removeByIndexes: 1 2 3 4 batchProcessing: {} pipeProcessing: "hello" doubleOddNumbers: 1 2 3 4 parentNode: childNode: {} parentNodes: id: 0 id: 1 updateTree: text: "root" children: text: "child 1" data: {} children: text: "child 1.1" text: "child 2" data: {} children: text: "child 2.1" text: "child 2.2" usingIfToUpdate: value: 1 usingUnlessToUpdate: dataLoaded: false usingSwitchToUpdate1: 1 usingSwitchToUpdate2: value: true usingFilter: 1 2 3 4 5 unsetWithFilter: data1: true data2: false data3: true data4: false ;const specs = // you can change separator by using configure({ separator: /pattern/ }) "a.b.c.d.e.f": $set 100 "a.b.c.d.e": $set "newProp" 100 arrayPush: $push 1 2 3 4 5 objMerge: $assign age: 20 school: "A" // using obj method as modifier { return Math; } // toggle property itself toggleMe: $toggle // toggle child properties toggleMyProp: $toggle "done" "completed" unsetMyProp: $unset "data1" "data2" removeSecond: $splice 1 1 // remove array items by its value removeAppleAndBanana: $remove "Apple" "Banana" // using sub spec to update all array items // sub spec syntax [spec] // spec can be [action, ...args] or spec tree { a: { b: ....} } doubleItems: x * 2 // use action name instead of function swapItems: "swap" 0 1 // using sub spec to update all obj values increaseProps: x + 1 removeByIndexes: "removeAt" 3 1 batchProcessing: "batch" "set" "name" "Peter" "set" "age" 20 pipeProcessing: "batch" x x + " WORLD!!!" // apply sub spec for only odd numbers doubleOddNumbers: x * 2 x % 2 parentNode: // remove childNode its self from parentNode childNode: "unset" // remove item at index 1 from parentNodes array parentNodes: 1: "unset" updateTree: // using conditional spec to update all nodes which has text prop, exclude all data nodes "?": node && nodetext "set" "done" true // do same thing with pattern matching "?/text/i": "set" "deleted" true children: // using diff spec for each node "?"node prop if node && nodetext return prop % 2 === 0 ? "set" "isEven" true : "set" "isOdd" true; return undefined; usingIfToUpdate: "if" x % 2 === 0 "set" "isEven" true "set" "isOdd" true usingUnlessToUpdate: "unless" xdataLoaded "set" "text" "loading..." usingSwitchToUpdate1: "switch" 1: "set" "one" 2: "set" "two" default: "set" "other" usingSwitchToUpdate2: "switch" xvalue ? "male" : "female" male: "set" "sex" "male" default: "set" "sex" "female" usingFilter: "filter" x % 2 === 0 unsetWithFilter: "unset" !!value;const result = ;not;;
Typescript support
immhelper.d.ts
declare declare ;;
Usages
/// ;;;// this is shorter way but there are some limitations// 1. Do not try to get prop value from obj, using originalState to get value instead// 2. Only mutating actions are allowed// 3. Mutating actions must be defined by using define(actionName, func) or define({ actionName: func });console.lognewState1, newState2;
Mutating actions
['push', ...items]
actions.push(target, ...items)
actions.$push(target, ...items)
[$push, ...items]push() all the items in array on the target
['pop']
actions.pop(target)
actions.$pop(target)
[$pop]
['unshift', ...items]
actions.unshift(target, ...items)
actions.$unshift(target, ...items)
[$unshift, ...items]unshift() all the items in array on the target.
['splice', index, count, ...items]
actions.splice(target, index, count, ...items)
actions.$splice(target, index, count, ...items)
[$splice, index, count, ...items]splice() remove item at specified index and push new items at there.
['remove', ...items]
actions.remove(target, ...items)
actions.$remove(target, ...items)
[$remove, ...items]remove specified items from target array
['removeAt', ...indexes]
actions.removeAt(target, ...indexes)
actions.$removeAt(target, ...indexes)
[$removeAt, ...indexes]remove items from array by indexes
['set', value]
actions.set(target, value)
actions.$pop(target, value)
[$set, value]replace the target entirely.
['set', prop, value]
actions.set(target, prop, value)
actions.$set(target, prop, value)
[$set, prop, value]set value for specified prop of the target
['toggle']
actions.toggle(target)
actions.$toggle(target)
[$toggle]toggle target's value.
['toggle', ...props]
actions.toggle(target, ...props)
actions.$toggle(target, ...props)
[$toggle, ...props]toggle all prop values of the target
['unset', ...props]
actions.unset(target, ...props)
actions.$unset(target, ...props)
[$unset, ...props]remove keys from the target object or set undefined for array indexes
['assign' ...objects]
actions.assign(target ...objects)
actions.$assign(target, ...objects)
[$assign, ...objects]copy the values of all enumerable own properties from one or more source objects to a target object
define(actionName, actionFunc, disableAutoClone)
define new mutating action, if disableAutoClone = true, original value will be passed instead of cloned value. Set disableAutoClone = true if you want to handle value manually, return original value if no change needed.
;
Special use cases
;; ; const state = counter: 0 ; ;;
Define custom mutating actions
;;