-
-
Notifications
You must be signed in to change notification settings - Fork 652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extra re-renders with selectable list #1175
Comments
https://codesandbox.io/s/jotai-select-list-forked-p4zzwk Nothing is wrong. React runs render function and finds that atom values are the same, and stop rendering (no commit). This behavior is basically the same as |
@moroshko I think your algorithm could be improved if you really need to focus on performances. Here is a schema of your pattern:
Here's how you could avoid the extra re-renders:
const selectedAtom = atom<Record<string, boolean>>({});
const updateToggle = atom(null, (get, set, payload) => {
const { id, atom, value } = payload
set(selectedAtom, prev => ({ ...prev, [id]: value}))
set(atom, value)
})
const Item = (props) => {
const { item, initialSelection } = props
const reference = React.useRef(atom(props.initialSelection))
const toggle = useAtomValue(reference.current)
const updateToggle = useSetAtom(updateToggle)
// ...
const onPress = () => {
updateToggle({ id: item.id, value: !toggle, atom: reference.current })
}
return (null)
}
const List = (props) => {
const initialSelection = useAtomValue(selectedAtom)
// Stop listening changes after first mount
return React.useMemo(() => {
const renderItem = (item) => {
const value = initialSelection[item.id]
return (
<Item item={item} initialSelection={value} />
)
}
return props.items.map(renderItem)
}, [])
}
const Component = () => {
return (
<List items={items} />
)
} That way, the toggled item is the only one re-rendered. To be honest, for such a simple example, I'd prefer my code cleaner and more maintainable, accepting more cheap re-renders. But there may be cases where this pattern could be useful I suppose. |
@dai-shi I think we can close it as it's all intended behaviour. I even tried to provide a work-around if needs be to avoid extra-renders (can't remember if I tested it, tho, but looks more like a react problem than jotai problem anyway) OP could still add a comment to re-open if need more info. |
Yeah. |
@dai-shi Yeah. We could add a "Performance" guide. It would tackle:
Otherwise, I don't know where to put something like this, it's pretty much how react behaves too: re-render the parent will re-caclulate the children (aka useReducer) I could try to propose a PR for this, I'm pretty interested in this topic |
No, I didn't mean "Performance" guide, which sounds interesting as another topic though. What I mean is, extra re-render without commit is an expected/intentional behavior, which is the default behavior of useReducer in React 18, and nothing needs to be worried. |
@dai-shi Well, that fits performance concerns to me :p Why would someone care about extra-renders if not for saving some calculation for performance purposes? Where else would you put that note? When first talking about derived atoms in "Primitves" ?
I'll think about it |
I know where you come from, but I strongly want to discuss from a different angle.
That sound like a good idea. btw, @sandren and I talked about an idea of combining "Primitive" section and "Core API" section. |
😅😅
Yeah sounds resaonable. Its just gonna be a "Note:" after all, and its pretty core/primitive related. I got convinced again!
Yup. And we can't omit it in our future Performance tab, right? :p
Yup
Yep this was part of one of my proposition too, for re-ordering the menu. Looking forward to it! |
Closing it in favor of the 2 seperate PR's. |
Given a list of selectable items, when an item's selection is toggled, I'd like only that item to be re-rendered.
However, I see that ALL items are getting re-rendered.
What am I doing wrong?
Use case: Select items to perform bulk action of the selected item ids.
CodeSandbox
The text was updated successfully, but these errors were encountered: