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

Fiber: Fix reentrant mounting in synchronous mode #8623

Merged
merged 1 commit into from
Dec 22, 2016

Conversation

sophiebits
Copy link
Collaborator

@sophiebits sophiebits commented Dec 22, 2016

We have to set the container in a way that it can be retrieved before we run any user code that could start a new top-level renderer. This API feels about as good to me.

@sophiebits sophiebits changed the title Test case for reentrant mounting in synchronous mode Fiber: Fix reentrant mounting in synchronous mode Dec 22, 2016
@@ -141,13 +134,20 @@ module.exports = function<T, P, I, TI, C, CX>(config : HostConfig<T, P, I, TI, C
const root : FiberRoot = (container.stateNode : any);
const current = root.current;

root.pendingContext = getContextForSubtree(parentComponent);
const context = getContextForSubtree(parentComponent);
if (root.context === null) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This seems gross. If I always set pendingContext instead, this test fails, because hasContextChanged() returns true and we rerender Middle despite element equality:

expect(ops).toEqual(['Foo', 'Bar', 'Bar']);

This is because the root hasn't completed when we do the update and so .pendingContext hasn't been moved to .context yet. (?) I think I'm missing something here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@acdlite Keeping pendingContext on the root fiber seems fragile and doesn't work correctly with incremental. Can we move it to the update queue of the host root now?

On the other hand, this is all just a temporary hack until we can switch to portals.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah putting it on the updateQueue seems reasonable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can't figure out how to do this. Will let you do it if you want.


scheduleTopLevelUpdate(current, element, callback);

if (__DEV__) {
if (ReactFiberInstrumentation.debugTool) {
if (element === null) {
if (current.type === null) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is this right? Not sure on this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is always true. If you wanted to check if this was a HostRoot, you'd check the tag, but even if you did this would always be true.

Instead you could probably check if there is an .alternate before calling scheduleTopLevelUpdate. That's usually how we determine if something is initial mount or not.

Copy link
Collaborator

@sebmarkbage sebmarkbage Dec 22, 2016

Choose a reason for hiding this comment

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

It begs the question though... What if element === null and it was the initial mount? E.g. if you unmount in componentDidMount. I suppose we pretend it never happened?

Copy link
Collaborator

Choose a reason for hiding this comment

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

What if you do a reentrant update from within a synchronous mount?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

How about current.child === null?

I will also move this above the scheduleTopLevelUpdate because that sounds closer to how it works with non-synchronous priority and if we don't then onUpdateContainer is called before onMountContainer due to the reentrancy (the update is called from the mount and finishes before the mount does)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh, the alternate works as you suggested.

@sebmarkbage
Copy link
Collaborator

Ok. Interesting one. Will look tomorrow but seems like @acdlite might have some insight.

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.

Looks good to me! I like the createContainer API. We'll likely need to change the public API to something like this once we enable time-slicing, anyway, so this gives us a head start.

I'll let @gaearon or @bvaughn comment on the context change.

@sophiebits sophiebits merged commit 13980e6 into facebook:master Dec 22, 2016
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