skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    As 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];
            });
        }, []);
    

  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search