I am trying to implement a property (real estate) chain
Each chain item should know which chain item is above/below it
A chain item can have its own sub-chain, and this in turn applies to its sub-chain items as well and so on
Visually like this
[
{ id: 1, belowId:0 },
{
id: 0,
belowId:2,
aboveId:1,
subChain: [
{ id:3, subChain: [{ id:4}] }
]
},
{ id: 2, aboveId:0 }
]
I tried this above structure but I started getting confused how to update nested items in state and ui
I am trying to implement a property (real estate) chain
Each chain item should know which chain item is above/below it
A chain item can have its own sub-chain, and this in turn applies to its sub-chain items as well and so on
Visually like this
[
{ id: 1, belowId:0 },
{
id: 0,
belowId:2,
aboveId:1,
subChain: [
{ id:3, subChain: [{ id:4}] }
]
},
{ id: 2, aboveId:0 }
]
I tried this above structure but I started getting confused how to update nested items in state and ui
Share Improve this question edited Jan 6 at 16:25 Hitmands 14.2k4 gold badges40 silver badges77 bronze badges asked Nov 18, 2024 at 23:18 RaffiRaffi 7571 gold badge9 silver badges22 bronze badges 15 | Show 10 more comments3 Answers
Reset to default 1As no one has answered my question, maybe I wasn't clear enough too to be fair. I will answer it here so that if someone stumbles on a similar problem.
So the main idea is that you want to flatten the array and make sure that subChain
only consist of ids
not references.
Here is how the ChainItem
look like (state structure)
type ChainItem = {
id: string;
root: boolean;
subChain: string[];
aboveId?: string;
belowId?: string;
parentId?: string;
};
I create an item with this utility method
const createItem = (id: number, root: boolean = false): ChainItem => {
return { id: `${id}`, root, aboveId: null, belowId: null, parentId: null, subChain: [] };
};
How it looks in the UI
interface ChainTreeItem extends Omit<ChainItem, "subChain"> {
subChain: ChainTreeItem[];
}
I build the UI tree like this
const buildTree = (chain: ChainItem[], id: string) => {
const itemMap = new Map(chain.map(item => [item.id, item]));
const build = (id: string): ChainTreeItem | null => {
const item = itemMap.get(id);
if (!item) return null;
return {
...item,
subChain: item.subChain.map(subId => build(subId))
};
};
return build(id);
};
React
state
const [chain, setChain] = useState<ChainItem[]>([createItem(0, true)]);
const chainTree: ChainTreeItem[] = useMemo(() => {
return chain.filter(property => property.root).map(property => buildTree(chain, property.id));
}, [chain]);
Create a sibling
const addSibling = useCallback((id: string, position: "above" | "below") => {
const isAddAbove = position === "above";
setChain(prev => {
let parent: PropertyItem | null = null;
const newItem = createItem(prev.length);
let updated = prev.map(item => {
if (item.id === id) {
parent = prev.find(itm => itm.id === item.parentId);
if (isAddAbove) {
newItem.belowId = item.id;
return { ...item, aboveId: newItem.id };
} else {
newItem.aboveId = item.id;
return { ...item, belowId: newItem.id };
}
}
return item;
});
if (parent) {
newItem.parentId = parent.id;
updated = updated.map(item => {
if (item.id === parent.id) {
return {
...item,
subChain: isAddAbove ? [newItem.id, ...item.subChain] : [...item.subChain, newItem.id]
};
}
return item;
});
} else {
newItem.root = true;
}
return isAddAbove ? [newItem, ...updated] : [...updated, newItem];
});
}, []);
Create a sub chain
const addRight = useCallback((id: string) => {
setChain(prev => {
const newItem = createItem(prev.length);
const updated = prev.map(item => {
if (item.id === id) {
newItem.parentId = item.id;
return { ...item, subChain: [...item.subChain, newItem.id] };
}
return item;
});
return [...updated, newItem];
});
}, []);
You should look into a state management library like Redux. With Redux you'll have a global state store that all of your components can pull from.
Listing below the two key characteristics of the requirements:
a. Each chain item should know which chain item is above/below it
b. A chain item can have its own sub-chain, and this in turn applies to its sub-chain items as well and so on.
To avoid mutation of objects in React, the code needs to work as below:
a. For a change in any object in a sub-chain, the whole containing object must be rebuilt. However, the objects nested inside the changed object will be unaffected. Similarly, the other containing objects if any in the same sub-chain will also be unaffected. This point is further explained below with an example.
Example
subChain: [{ id:3, subChain: [{ id:4, subChain : [{ id: 5 }]}]}, {id : 6}]
When the object { id:4, subChain : [{ id: 5 }]} changes, then the whole containing object { id:3, subChain: [{ id:4, subChain : [{ id: 5 }]}]} must be rebuilt. However the nested object in the changed object { id: 5 } will remain unaffected. Similarly the other containing in the same sub-chain object{id : 6} will also be unaffected.
As the whole containing object in a sub-chain is always changed here, this change will cascade to the main-chain. Point b states the same.
b. For a change in any object either in the main chain or in a sub-chain , the whole main chain needs to be rebuilt.
case 1 : a change in a sub-chain as explained in point a.
For a change in the object { id:4, subChain : [{ id: 5 }]}, the object { id : 0, … } must be rebuilt since a containing object in its sub-chain has been changed. The newly rebuilt object will also call for re-building the objects above and below which will result a whole rebuilding process for the entire main chain.
{
id: 1,
belowId: 0,
},
{
id: 0,
belowId: 2,
aboveId: 1,
subChain: { id: 3, subChain: { id: 4, subChain: { id: 5 } } },
},
{
id: 2,
aboveId: 0,
},
case 2 : a change in the main-chain
When the object { id : 0, …} changes, this is a direct change in the object which is separate from the changes in its sub-chain. let us say, its id is changing from 0 to 100. Therefore the same object must be newly built. Now the objects above and below will also be affected by this change. And it will call for the whole main-chain to be rebuilt. However the sub-chains in all objects in the main chain will remain unaffected.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745589239a4634731.html
subChain
arrays should not contain object references but just ids. This means you won't have to traverse nested objects (or even search through them) to update anything; although you'll have to look up the structure when consuming the tree. – Bergi Commented Nov 19, 2024 at 2:18