Skip to content

Replace ancestorComponent with vnode parent pointer (+5 B)#1688

Merged
marvinhagemeister merged 7 commits into
masterfrom
parent-pointer
Jun 9, 2019
Merged

Replace ancestorComponent with vnode parent pointer (+5 B)#1688
marvinhagemeister merged 7 commits into
masterfrom
parent-pointer

Conversation

@andrewiggins

@andrewiggins andrewiggins commented Jun 6, 2019

Copy link
Copy Markdown
Member

Summary

This is pre-req for #1689 (which fixes #1593, #1604, #1605).

As a side benefit, it continues to normalize our VNode structure to make our virtual tree easier to reason and work with.

2b087d5 Replace ancestorComponent with parent vnode pointer (+8 B)
52f2161 Move _depth property to VNode (-3 B)

Breaking changes

catchError and catchRender now take VNodes as their arguments instead of Components

Comment thread src/diff/index.js Outdated
Comment thread src/index.d.ts
diffed?(vnode: VNode): void;
/** Attach a hook that is invoked after an error is caught in a component but before calling lifecycle hooks */
catchError?(error: any, component: Component): void;
catchError?(error: any, vnode: VNode): void;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wondering if there would be a use for vnodes here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Honestly, I don't think there really is... I'm not super happy with this change. I have more thoughts about this. Will post more soon

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Personally, I don't mind the change for now. It could prove useful in the future for preact/debug. We could theoretically catch top-level errors and display a nice message in the console.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

#1692 contains where my brain went when making this change. Let me know what you think!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome, marking it as private is an even better solution 👍

@coveralls

coveralls commented Jun 7, 2019

Copy link
Copy Markdown

Coverage Status

Coverage increased (+0.0003%) to 99.776% when pulling 4170502 on parent-pointer into df27a6f on master.

@JoviDeCroock JoviDeCroock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Personally I really like this change, it's more intuitive reasoning about a parentVnode (having 1 depth difference) instead of an ancestorComponent (having x difference). I'm not misunderstanding this I hope?

Great work Andre!

Comment thread src/diff/index.js Outdated
Comment thread src/diff/index.js Outdated
* Unmount a virtual node from the tree and apply DOM changes
* @param {import('../internal').VNode} vnode The virtual node to unmount
* @param {import('../internal').Component} ancestorComponent The parent
* @param {import('../internal').VNode} parentVNode The parent

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The comment here still refers to a "parent component" rather than a vnode. Can the parent VNode be obtained via the vnode._parent link here instead of passing an argument?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks! I'll update the comment. Since this function is recursive, I wanted to keep parentVNode as a pointer to first parent that isn't being unmounted, thinking it should handle errors of children that are being unmounted (should an unmounting error boundary still handle errors for children as they are unmounted?). However, let me check what React does here... perhaps we can save some bytes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm seems React does swallow errors if the nearest error boundary to a thrown error is being unmounted (https://codesandbox.io/s/react-throwing-unmount-1vdvn) (<- could someone double check me on this?)

I think I'll leave our behavior for now just cuz I think I'd prefer to make noise on errors (e.g. failing to unsubscribe some resource which could lead to a memory leak).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agree, swallowed errors is always painful to debug 👍

describe('#componentDidCatch', () => {

/** @type {Error} */
let expectedError;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@rpetrich FYI, I've updated the error boundary tests a bit. Lemme know if you have any thoughts!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think the biggest change is specifying that throwing refs can be caught in the component that defines them

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Updated error boundary tests look good and check more behaviour 👍

@marvinhagemeister marvinhagemeister left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I really like this change as it makes upwards traversal a lot more intuitive and will make it easier to fix the remaining Fragment issues for good. Thank you so much for the PR 👍 💯

@robertknight

Copy link
Copy Markdown
Member

To check my understanding, does every vnode now have a parent pointer, regardless of type (dom, component or fragment)? This means to get the ancestor component, it might be necessary to follow several parent pointers up the tree until we get to a component node?

@robertknight robertknight left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks good to me. The effort to normalize the vnode tree structure makes sense.

@marvinhagemeister

Copy link
Copy Markdown
Member

@robertknight yup, your comment describes the changes perfectly 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants