I stored a tree data structure in React state and used React Table to render the tree data. As the tree data structure is complicated, I also used immer to update the state.
I created a simplified version in sandbox to demo the problem: a parent-child tree is stored in React state, a React table renders each child node as an number input box, and renders each parent node to display total of its children's value.
The tree node class looks like this:
class TreeNode {
name: string;
isLeaf: boolean;
subtotal: number | null = null;
value: number | null = null;
children: TreeNode[] = [];
constructor(name: string, children?: TreeNode[]) {
this.name = name;
this.isLeaf = !children?.length;
if (children?.length) this.children = children;
}
}
React table provides an Id (e.g. '0.0'
) for each row so that I can locate to the related child in the state, also its parent when a child is updated, and update their value / subtotal accordingly:
const updateTableData = (rowId: string, val: number) => {
setTableData(
// Using immer produce
produce((draft) => {
// Locate updated child and parent omitted
...
if (updatedItem) {
console.log("updatedItem is", updatedItem.name);
updatedItem.value = val;
}
if (parentItem) {
console.log("updatedItem's parent is", parentItem.name);
parentItem.subtotal = (parentItem.subtotal ?? 0) + val;
}
})
);
};
However after the state is updated, the React table (specifically the affected cells) do not re-render to reflect the change.
I am not familiar with React table, also didn't store such complicated tree data into React state before. I am not sure if the problem is caused by React table or something else.
As I am using React table, the code looks a bit lengthy but I highlighted the key parts with comments. Many thanks for your patience and help.
Update 1
It turned out that immer does not support classes well. I updated my code following the instruction, it's re-rendering now, but still not updating the state properly.
So I updated my question title to How to update tree data structure in React state. I know it is not good idea to store complicated/nested data in React state but in my case to use the expandable feature of React table, I have to create a tree data structure.
I ended up refactoring my code by replacing the
TreeNode
class with recursive traversal function, a bunch of util function and plain objects instead. Withimmer
it's working fine and the performance is acceptable.