Skip to content
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

setState() in componentDidMount() should flush synchronously even with createBatch() #12466

Merged
merged 6 commits into from
Mar 29, 2018

Conversation

gaearon
Copy link
Collaborator

@gaearon gaearon commented Mar 27, 2018

I think this is a bug but I'm not familiar enough with the batching API to be sure. This is what Alan bumped into with UFI2.

My attempt at fixing is in 7e3a38b.

@acdlite acdlite self-requested a review March 27, 2018 21:43
@gaearon gaearon changed the title Failing test: setState() inside componentDidMount() is applied asynchronously during batch.commit() setState() in componentDidMount() should flush synchronously even with createBatch() Mar 28, 2018
do {
performWorkOnRoot(root, expirationTime, false);
findHighestPriorityRoot();
} while (nextFlushedRoot === root && nextFlushedExpirationTime === Sync);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loops are scary. Are we sure we need this?

Copy link
Collaborator Author

@gaearon gaearon Mar 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically performWorkOnRoot is called inside a loop that finds next thing to work on until there's none.

flushRoot is special because it wants to flush "just one" root. So it only called performWorkOnRoot once. This is why it didn’t flush setState in commit lifecycles (they're just like flushing the same root twice—if my mental model is right).

There could be more than one cascading update. So it seems like a loop is necessary.

I'm not sure those are the right exit conditions though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I'm not feeling confident in this. There are other things performWork does that performWorkOnRoot doesn’t. For example scheduling a deferred callback for leftover work. I’m not sure if missing this here means it would get dropped. I wonder if we could reuse the rest of the scheduler code, but teach the scheduler the concept of the "current" batch which gets committed in isolation if it exists.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also not sure what would happen if we used flushSync to schedule another root inside a currently committed batch's lifecycle.

acdlite added 3 commits March 28, 2018 18:28
Call performSyncWork right after flushing the batch. Does effectively
the same thing by reusing the existing function.

Also added some comments.
Copy link
Collaborator

@acdlite acdlite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed some nits and some additional comments. Looks good to me.

@gaearon gaearon merged commit 7a833da into facebook:master Mar 29, 2018
rhagigi pushed a commit to rhagigi/react that referenced this pull request Apr 19, 2018
…h createBatch() (facebook#12466)

* Add a failing test for setState in cDM during batch.commit()

* Copy pasta

* Flush all follow-up Sync work on the committed batch

* Nit: Use performSyncWork

Call performSyncWork right after flushing the batch. Does effectively
the same thing by reusing the existing function.

Also added some comments.

* Delete accidentally duplicated test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants