-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
18 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
selector(ref.current.value)
can read from stale props if selector is:state => state[props.someId]
.This is the problem with selectors using props. It is not safe to read from props if they will be eagerly evaluated and they have to be eagerly evaluated to see if the derived value has changed.
26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JeremyRH Thanks for the comment. I understand that's one of the biggest question.
What I assume is:
So, there should be no stale props issue like react-redux v7.1. The remaining concern is performance because it re-subscribes every time props change, or every time it renders if the selector isn't wrapped by useCallback.
26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use a ref for the selector to avoid re-subscribes:
26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JeremyRH
It absolutely works in legacy mode. But from my experience in reduxjs/react-redux#1509, refs won't work well in concurrent mode.
One of the issues in your snippet is
selectorRef.current = selector;
. In CM, after this line, React will throw away the result without committing, which ends up keeping an improper selector in the ref.26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are calling the selector outside of the render phase (inside listener) and it is only used to schedule a new render. I don’t think it matters if
selectorRef.current
is an improper selector. Maybe if the improper selector prevented a new render it would be an issue but I don’t know how that can happen.getSnapshot
would not useselectorRef.current
so it would always use a proper selector.26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the improper selector can prevent triggering re-render, which is an issue. That can happen.
You are probably right about
getSnapshot
. I wasn't aware that. So, we might not even need useCallback?26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you show an example? When React renders but does not commit, doesn't React automatically schedule a new render or commit for later?
You need it for
subscribe
or else it will resubscribe every render but newgetSnapshot
functions do not cause resubscribes.26c8a16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really hard to show it in an easy way. You could see the thrown-away behavior in https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-mode. It won't show all the counts.
It will usually schedule a new render (without commit).
But, it fails to re-use the previous snapshot. Found this description in the RFC: