Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@joecritch
Last active October 10, 2017 10:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joecritch/66e332acdc1327a24677b0d2ce33ba1f to your computer and use it in GitHub Desktop.
Save joecritch/66e332acdc1327a24677b0d2ce33ba1f to your computer and use it in GitHub Desktop.
Immutable tree "updateIn"
function updateIn(tree, indexPath, replacement, childrenKey = 'children', depth = 0) {
function insert(ins) {
return tree
.slice(0, indexPath[depth])
.concat([ins])
.concat(tree.slice(indexPath[depth] + 1));
}
const lastDepth = indexPath.length - 1;
// Edge case: reached the leaf node.
if (depth === lastDepth) {
if (replacement === null) {
// Remove the node at last index
return tree.filter((el, idx) => idx !== indexPath[depth]);
}
return insert(replacement);
}
let node = tree[indexPath[depth]];
if (node[childrenKey] && depth < lastDepth) {
// Recursive case: we've hit a Block along the index path
node = {
...node,
[childrenKey]: updateIn(node.children, indexPath, replacement, childrenKey, depth + 1),
};
}
// Return case
return insert(node);
}

updateIn

Replaces a node in a tree's given index path, and returns a new object. Reuses existing objects where possible.

Useful for updating recursive & immutable data structures in React or Redux.

usage

const tree = [
  {
    name: 'parent',
    children: [
      {
        name: 'child 1',
      },
      {
        name: 'child 2',
      },
    ],
  },
  {
    name: 'another parent',
    children: null,
  },
];

const newTree = updateIn(tree, [0, 1], { name: 'child 2a' });

// newTree shape:
// [
//   {
//     name: 'parent',
//     children: [
//       {
//         name: 'child 1',
//       },
//       {
//         name: 'child 2a',
//       },
//     ],
//   },
//   {
//     name: 'another parent',
//     children: null,
//   },
// ]

// equality:
// newTree !== tree
// newTree[0] !== tree[0]
// newTree[0].children[0] === tree[0].children[0]
// newTree[0].children[1] !== tree[0].children[1]
// newTree[1] === tree[1]

removing a node

const newTree = updateIn(tree, [0, 1], null);
  • pass null as the replacement
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment