How to prevent re-rendering of component when selectorFamily state remains unchanged?
See original GitHub issueHi,
Really love Recoil, and have started using it in a project quite extensively. I clearly see the potential of this state mgmt library. I have setup an app with multiple atoms and selectors, and it all works very smooth, however, I have one scenario that I have yet to solve in a clever manner, and I have not been able to find more info about it on your docs.
I have a table with multiple rows. Each row is a React.memo sub-component that uses Recoil hooks. The Recoil part of the component looks as follows (excuse my variable namings):
const setMarkInvalidModalState = useSetRecoilState(markInvalidModalState)
const setMarkInvalidSelectTrade = useSetRecoilState(markInvalidSelectTradeState)
const setOpenTradeModal = useSetRecoilState(openTradeModalState)
const setOpenTradeSelectTrade = useSetRecoilState(openTradeSelectTradeState)
const markForTrade = useRecoilValue(getMarkForTrade(compositeKey));
The only place i subscribe for updates and re-renderings is useRecoilValue of getMarkForTrade. getMarkForTrade
is a selectorFamily
, that looks as follows:
const getMarkForTrade = selectorFamily({
key: 'MarkForTradeState',
get: (compositeKey: string) => ({get}) => {
const allMarks = get(getTradeMarks);
const mark = allMarks[compositeKey];
return ( mark !== undefined ? mark : null) as TradeMark | null;
},
});
Now, whenever the underlying selector getTradeMarks
(called in getMarkForTrade
) is updated, all components subscribed to getMarkForTrade
is also getting re-rendered. Even though the output / state of getMarkForTrade
has remained unchanged for the input.
Basically all rows in the table are re-rendered every time, although 90% of the rows have the same output state from getMarkForTrade
.
How can I prevent this? I have tested multiple times that this is the selector that triggers the re-render.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:7
- Comments:5 (3 by maintainers)
Top GitHub Comments
I’ve been using this in the same situation, a table where only the row that was changed gets re-rendered.
Doesn’t work with promises and just uses !== to compare, but both could be supported by simple changes to the code.
In my opinion, the best built-in solution would be that the selector is passed the old value to the get function and the selector can implement any checks or whatnot itself. You can see in #314 that it is hard to implement a generic method of suppressing updates so my idea is:
This way selectors that don’t care just ignore the old input and the few selectors which need to suppress downstream updates can implement checks at the beginning of the function.
maybe related https://github.com/facebookexperimental/Recoil/pull/825