Skip to content

Instantly share code, notes, and snippets.

@smagch
Last active June 18, 2022 09:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smagch/e4beeefc378085377ed8a4a7478a47d8 to your computer and use it in GitHub Desktop.
Save smagch/e4beeefc378085377ed8a4a7478a47d8 to your computer and use it in GitHub Desktop.
recursive reducer demo

Recursive reducer demo

The script reducer.ts demonstrates reducer implementation for tree-structured data.

type Item = {
id: string;
items: Item[];
};
type Action =
| {
type: "INSERT_BEFORE",
targetId: string,
item: Item,
};
function insertBeforeItem(sourceItem: Item, newItem: Item, targetId: string): Item {
// No children
if (sourceItem.items.length === 0) {
return sourceItem;
}
// Find the target in `sourceItems`'s children
const index = sourceItem.items.findIndex(item => item.id === targetId);
if (index !== -1) {
const newItems = sourceItem.items.slice();
newItems.splice(index, 0, newItem);
return {
id: sourceItem.id,
items: newItems,
};
}
// Call recursively in the hope of finding the target in descendents.
for (const [i, item] of sourceItem.items.entries()) {
const maybeNewItem = insertBeforeItem(item, newItem, targetId);
if (maybeNewItem !== item) {
const newItems = sourceItem.items.slice();
newItems[i] = maybeNewItem;
return {
id: sourceItem.id,
items: newItems,
};
}
}
// Target not found
return sourceItem;
}
function reducer(item: Item, action: Action): Item {
switch (action.type) {
case "INSERT_BEFORE": {
return insertBeforeItem(item, action.item, action.targetId);
}
default: {
return item;
}
}
}
const rootItem = {
id: "root",
items: [
{
id: "column-1",
items: [
{
id: "column-1-row-1",
items: [
{
id: "column-1-row-1-block-1",
items: [],
},
{
id: "column-1-row-1-block-2",
items: [],
}
],
},
{
id: "column-1-row-2",
items: [
{
id: "column-1-row-2-block-1",
items: [],
},
{
id: "column-1-row-2-block-2",
items: [],
}
],
},
],
},
{
id: "column-2",
items: [
{
id: "column-2-row-1",
items: [
{
id: "column-2-row-1-block-1",
items: [],
},
{
id: "column-2-row-1-block-2",
items: [],
}
],
},
{
id: "column-2-row-2",
items: [
{
id: "column-2-row-2-block-1",
items: [],
},
{
id: "column-2-row-2-block-2",
items: [],
}
]
},
],
}
]
}
const dispatchAndLog = (action: Action) => {
const updatedRootItem = reducer(rootItem, action);
console.log(JSON.stringify(updatedRootItem, undefined, 2));
console.log("---");
};
dispatchAndLog({
type: "INSERT_BEFORE",
targetId: "column-2-row-2",
item: {
id: "item-before--column-2-row-2",
items: [],
}
});
dispatchAndLog({
type: "INSERT_BEFORE",
targetId: "column-1-row-1-block-2",
item: {
id: "item-before--column-1-row-1-block-2",
items: [],
}
});
dispatchAndLog({
type: "INSERT_BEFORE",
targetId: "column-2",
item: {
id: "item-before--column2",
items: [],
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment