I’m developing one of my projects with React, and I need to create some list where each item represents a table row, and is dependent on the previous line (and partially on the next line) – similar to how Excel or Google Sheet works.
Say each item has three fields, a
, b
and c
. Each item updates its own a
field depending on the a
field of the previous item, and updates its b
field depending on the c
field of the next one.
My current design is to hold each item as a separate component (rendering the table row), and to hold 2 lists in the parent component – one for the states of each item, and one for the items themselves.
Looks something like this:
interface ItemState {
a: number,
b: number,
c: number,
}
function ItemComponent({prevState, nextState, state, setState}:
{prevState: ItemState; nextState: ItemState; state: ItemState; setState: (state: ItemState) => void;}) {
React.useEffect(() => {
setState({...state, a: a+1});
}, [prevState.a]);
React.useEffect(() => {
setState({...state, b: c-1});
}, [nextState.c]);
return (<...>); // table row
}
function ParentComponent() {
const [stateList, setStateList] = React.useState<ItemState[]>([item1, item2, item3]);
const mapState = React.useCallback(
(prev: ItemState | null, curr: ItemState, next: ItemState | null) => {
return (
<ItemComponent
key={"someUniqueId"}
prevState={prev}
nextState={next}
state={curr}
setState={"some function which sets a specific item in the list based on id"}
/>
);
},
[]
);
const itemList = React.useMemo(
() =>
stateList.map((state, i) => {
const prev = i === 0 ? null : stateList[i - 1];
const next = i === stateList.length - 1 ? null : stateList[i + 1];
return mapState(prev, stintState, next);
}),
[stateList, mapState]
);
return (<...>); // rendered table containing the itemList
}
(Obviously this is a simplified version, in reality I perform more complex calculations over more fields than just a
, b
and c
.)
This solution works. However, it’s performance is terrible, as I normally have much more than just 3 items in the list, causing it to take a significant amount of time to update all of the decedents when one item is updated.
Moreover, when the list contains over ~14 items I start getting “Maximum update depth exceeded” errors, caused by the large amount of setState
s inside useEffect
s.
I’m sure there’s a much more elegant and performative solution to this problem, I just couldn’t figure it out myself – and I’d love to get some help on that.