Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
fix CM tearing #1455
fix CM tearing #1455
Changes from 3 commits
b986030
9c0520f
3d52f3a
647195d
d248d0a
eb6f8cf
6647836
5ed652c
16a6253
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
To be CM friendly, could we do something like:
So we could do this, for example:
In React docs, it's using something like:
const value = resource.read()
where
read()
either returns the value or throws so it can bail out before the selector is set. Not sure if here is the best place to do it, but yeah, with CM not everything "thrown" is an error.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.
sorry i think that thow promise to comunicate with Suspense does NOT matter with useSelector, that has to select a state without tearing on render. that's another problem.
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.
this changes the whole point of the test. this test ensures that
mapState
never sees inconsistent state. with this change you are asserting the exact oppositeThere 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.
Because we NO more read the last state in the render phase, the "parent-child-issue" is resolved with 2 render, as every change of the store make 2 event-callback one on the parent and one on the child.
Before the issue was resolved with the "hack" of reading always the fresh Store state, even if we are on the "preview" scheduled refresh came out from "checkForUpdate" callback.
That hack while resolve the "parent-issue" with 1 render less, broke the changes normal queue on the the componente, that produce tearing on CM where every component could rendered in a random way, jumping the "changhes queue"
please try the demo of @dai-shi with my version and with old one. you will see the differences on a fast store changes, with slow render.
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.
If you are developing your own fork, it's fine and I think it's one possible approach.
But, if you would like to support all existing RR apps (which is necessary for the official RR), you want to keep the backward compatibility. As I said, it should be technically possible. Seems like you are used to the code base, I think you can do it. I'm not 100% sure though.
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.
@dai-shi i'm not dev my own fork, otherwise i havent opened a pr. that said i think that was a mistake reading fresh store state on render, to have 1 less render on that particular use case. Moreover it is of course back compatible with 1 render more (for that usecase)
Anyway i will try to explain better with a flow chart as soon as i can. That's all.
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.
The Exactly point is: when a componet render it MUST read the storeState that was from HIS last storeChangeCallback!. Otherwise reading in render store.getState() could be newer than HIS callback queque. THAT'S THE POINT. Think more about that. test the demo.
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 clarify what you mean by "more renders"? It sounds like you're saying we will cause additional render cycles to occur, which is going to be bad for performance.
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.
@markerikson I believe this is not due to an additional render. let me try to outline the order of events here:
it feels to me that tiered subscription and CM might just be incompatible
@salvoravida as @dai-shi pointed out, this discussion is not about the correctness of your change, but about preserving the existing behavior for backwards compatibility. there are likely tons of apps out there that have
mapStateToProps
written in a way that depends on the props and state being consistent. that's why it is important we think of a way to keep the existing behavior. in theuseSelector
hook we took the approach of simply ignoring these situations and dealing with errors by forcing a re-render. that was a deliberate decision we could make because it was a new API.connect
is sadly differentThere 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.
I don't understand this change. The whole purpose of this test was to ensure the selector never sees inconsistent state, not just on the latest render.
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.
Because we NO more read the last state in the render phase, the "parent-child-issue" is resolved with 2 render, as every change of the store make 2 event-callback one on the parent and one on the child.
Before the issue was resolved with the "hack" of reading always the fresh Store state, even if we are on the "preview" scheduled refresh came out from "checkForUpdate" callback.
That hack while resolve the "parent-issue" with 1 render less, broke the changes normal queue on the the componente, that produce tearing on CM where every component could rendered in a random way, jumping the "changhes queue"
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.
please try the demo of @dai-shi with my version and with old one. you will see the differences on a fast store changes, with slow render.