
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
reupdate can help you to:
reselect selectors used redux state: just create reducers with reupdatereupdate selectors (with same API as reselect)react componentsreupdate vs reselect: avoid extra recalculations (working test!)
redux + reupdate: avoid extra state changes (working test!)
Also includes comparation tests for:
reupdate has no dependencies to redux and react, etc. so you can use it with other frameworks.
object-path-immutable and immutability-helperTypically, the state changes less frequently than it is read.
To avoid extra re-evaluations (and re-rendering) with redux, reselect, react and others we should return same reference to the (maybe nested) state when it was updated but actually not changed (some isDeepEqual(state, nextState) gives true).
If your update of src value do not change it (in sense of deep equality) then result === src must give true:
isDeepEqual(src, value) |=> result === src
This rule also must work for nested not changed values as is:
isDeepEqual(src.a.b.c, value.a.b.c) |=> result.a.b.c === src.a.b.c
object-path-immutable and immutability-helperobject-path-immutable and immutability-helper usually expect that you know what is the difference from src and value and some times returns reference for value despite it is deep equal to src. As a result we have extra recalculations of selectors and/or re-rendering of components.
In such cases reupdate returns reference to src, so it prevents extra recalculations and re-rendering. Profit! See examples!
yarn add reupdate
or
npm i reupdate
import {set, setAt, extend} from 'reupdate';
import cloneDeep from 'lodash/cloneDeep';
const src = {
a: {
b: {
c: 'c',
d: 'd'
},
e: 'e',
f: [
{f0: 'f0'},
{f1: 'f1'},
{f2: 'f2'}
]
},
info: {
name: 'smth',
coord: {x: 1, y: 2}
}
}
let res;
res = set(src, src); // res === src
res = set(src, cloneDeep(src)); // res === src
res = setAt(src, 'a.f[1].f1', 123);
// res.a !== src.a
// res.a.f !== src.a.f
// res.a.f[1].f1 !== src.a.f[1].f1
/** But following references were saved!: */
// res.a.b === src.a.b
// res.a.e === src.a.e
// res.a.f[0] === src.a.f[0]
// res.a.f[2] === src.a.f[2]
res = extend(src, {
info: {
name: 'New Name',
coord: {x: 1, y: 2} // coord not actually changed
}
});
// res.info !== src.info
// res.info.name !== src.info.name
/** But following references were saved!: */
// res.a === src.a
// res.info.coord === src.info.coord
You can import functions like this:
import {set, insert, createSelector} from 'reupdate';
Or like this (to reduce bundle size with webpack or other bundlers):
import set from 'reupdate/set';
import insert from 'reupdate/insert';
import createSelector from 'reupdate/createSelector';
Returns value if newValue has nothing new (is deep equal to value).
Returns new object/array with:
Example:
import set from 'reupdate/set'
const src = {
name: 'Alex',
info: {
greeting: 'Hello',
description: 'I am developer'
},
address: {
country: 'Russia',
city: 'Moscow'
},
friends: [
{ name: 'Vasya', age: 25 },
{ name: 'Fedor', age: 33 }
]
};
const replacement = {
name: 'Alex',
info: {
greeting: 'Hello',
description: 'I am developer'
},
address: {
country: 'Russia',
city: 'Moscow'
},
friends: [
{ name: 'Vasya', age: 3 }, // The ONLY actual change!
{ name: 'Fedor', age: 33 }
]
};
const res = set(src, replacement);
expect(res).toEqual(replacement); // Correct result
expect(res === src).toBe(false);
expect(res.info === src.info).toBe(true); // Same reference!
expect(res.address === src.address).toBe(true); // Same reference!
expect(res.friends === src.friends).toBe(false);
expect(res.friends[0] === src.friends[0]).toBe(false);
expect(res.friends[1] === src.friends[1]).toBe(true); // Same reference!
set nested part of value
Example:
updateAt(state, 'a.b[1].c', c => c + 1)
Equal to setAt(value, path, undefined)
Important edge case: delete undefined value saves reference:
import deleteAt from 'reupdate/deleteAt';
const value = {x: 1};
const res = deleteAt(value, 'y');
// value === res
Params:
ObjectObject | Object => Object
srcReturns src if extensionOrCreator has nothing new (has deep equal only properties).
Returns new object with:
Important edge case: extend with empty extensionOrCreator saves reference: src === extend(src, {})
import extend from 'reupdate/extend';
const src = {
name: 'Alex',
info: {
greeting: 'Hello',
description: 'I am developer'
},
address: {
country: 'Russia',
city: 'Moscow'
},
friends: [
{ name: 'Vasya', age: 25 },
{ name: 'Fedor', age: 33 }
]
};
const extension = {
friends: [
{ name: 'Vasya', age: 3 }, // The ONLY actual change!
{ name: 'Fedor', age: 33 }
]
};
const res = extend(src, extension);
expect(res).toEqual({...src, ...extension}); // Correct result
expect(res === src).toBe(false);
expect(res.info === src.info).toBe(true); // Same reference!
expect(res.address === src.address).toBe(true); // Same reference!
expect(res.friends === src.friends).toBe(false);
expect(res.friends[0] === src.friends[0]).toBe(false);
expect(res.friends[1] === src.friends[1]).toBe(true); // Same reference!
extend nested object of value
Params:
string - lodash path stringextendImportant edge case: push empty values saves reference: srcArray === push(srcArray)
Example:
const state = {a: {b: [{x: 1}, {y: 2}]}}
const newState = pushAt(state, 'a.b', {z:3}, {w: 4})
// newState = {a: {b: [{x: 1}, {y: 2}, {z:3}, {w: 4}]}}
Important edge case: pushAt empty values saves reference: src === pushAt(src, 'a.b')
Important edge case: pop 0 items saves reference: srcArray === pop(srcArray, 0)
Important edge case: pop 0 items saves reference: src === popAt(src, 'a.b', 0)
Important edge case: insert empty values at any index saves reference: srcArray === insert(srcArray, i)
Important edge case: insert empty values at any index saves reference: src === insert(src, 'a.b', i)
Important edge cases:
values saves reference: srcArray === splice(srcArray, i, 0)values saves reference:
import splice from 'reupdate/splice';
const srcArray = [a, b, c, d];
const atIndex = 1;
const res = splice(srcArray, atIndex, 2, b, c);
// srcArray === res;
Important edge cases:
values saves reference: src === spliceAt(src, 'a.b', i, 0)values saves reference (see splice example)Important edge case: shift 0 items saves reference: srcArray === shift(srcArray, 0)
Important edge case: shift 0 items saves reference: src === shift(src, 'a.b', 0)
Important edge case: unshift empty values saves reference: srcArray === unshift(srcArray)
Example:
const state = {a: {b: [{x: 1}, {y: 2}]}}
const newState = pushAt(state, 'a.b', {z:3}, {w: 4})
// newState = {a: {b: [{z:3}, {w: 4}, {x: 1}, {y: 2}]}}
Important edge case: unshiftAt empty values saves reference: src === unshiftAt(src, 'a.b')
Wrapper for reselect.createSelector
Wrapper for reselect.createStructuredSelector
Run yarn test index to check that reupdate saves references.
Run yarn test object-path-immutable to check that object-path-immutable NOT saves references (some tests will fail).
Run yarn test immutability-helper to check that immutability-helper NOT saves references (some tests will fail).
FAQs
Selectors & React.PureComponent friendly immutable update
We found that reupdate demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.