Skip to content

Conversation

@gwwar
Copy link
Contributor

@gwwar gwwar commented Feb 23, 2022

While testing #38999 @ciampo found that DropZone was triggering a "Can't perform React state update on an unmounted component." warning

CleanShot 2022-02-23 at 14 38 29@2x

This PR fixes the issue by setting refs with callback functions to null when the cleanup function is called. Let me know if there is a more elegant way of working around this.

Before:

CleanShot.2022-02-23.at.14.34.43.mp4

After:

CleanShot.2022-02-23.at.14.37.15.mp4

Testing Instructions

  • No regressions to dropzone components used in blocks like image/gallery
  • verify that the React warning no longer fires.

@gwwar gwwar added [Type] Bug An existing feature does not function as intended [Package] Compose /packages/compose labels Feb 23, 2022
@gwwar gwwar requested a review from ellatrix February 23, 2022 22:43
@gwwar gwwar requested a review from ajitbohra as a code owner February 23, 2022 22:43
@gwwar gwwar self-assigned this Feb 23, 2022
@github-actions
Copy link

github-actions bot commented Feb 23, 2022

Size Change: +16 B (0%)

Total Size: 1.15 MB

Filename Size Change
build/compose/index.min.js 11.2 kB +16 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/admin-manifest/index.min.js 1.24 kB
build/annotations/index.min.js 2.77 kB
build/api-fetch/index.min.js 2.25 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 487 B
build/block-directory/index.min.js 6.49 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 143 kB
build/block-editor/style-rtl.css 14.8 kB
build/block-editor/style.css 14.8 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 445 B
build/block-library/blocks/button/editor.css 445 B
build/block-library/blocks/button/style-rtl.css 560 B
build/block-library/blocks/button/style.css 560 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 90 B
build/block-library/blocks/code/style.css 90 B
build/block-library/blocks/code/theme-rtl.css 131 B
build/block-library/blocks/code/theme.css 131 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-template/style-rtl.css 127 B
build/block-library/blocks/comment-template/style.css 127 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-query-loop/editor-rtl.css 95 B
build/block-library/blocks/comments-query-loop/editor.css 95 B
build/block-library/blocks/cover/editor-rtl.css 546 B
build/block-library/blocks/cover/editor.css 547 B
build/block-library/blocks/cover/style-rtl.css 1.57 kB
build/block-library/blocks/cover/style.css 1.57 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 965 B
build/block-library/blocks/gallery/editor.css 967 B
build/block-library/blocks/gallery/style-rtl.css 1.61 kB
build/block-library/blocks/gallery/style.css 1.61 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 159 B
build/block-library/blocks/group/editor.css 159 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 731 B
build/block-library/blocks/image/editor.css 730 B
build/block-library/blocks/image/style-rtl.css 518 B
build/block-library/blocks/image/style.css 523 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 199 B
build/block-library/blocks/latest-posts/editor.css 198 B
build/block-library/blocks/latest-posts/style-rtl.css 447 B
build/block-library/blocks/latest-posts/style.css 446 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 493 B
build/block-library/blocks/media-text/style.css 490 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 649 B
build/block-library/blocks/navigation-link/editor.css 650 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/view.min.js 375 B
build/block-library/blocks/navigation/editor-rtl.css 2.01 kB
build/block-library/blocks/navigation/editor.css 2.02 kB
build/block-library/blocks/navigation/style-rtl.css 1.89 kB
build/block-library/blocks/navigation/style.css 1.88 kB
build/block-library/blocks/navigation/view.min.js 2.85 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 363 B
build/block-library/blocks/page-list/editor.css 363 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/style-rtl.css 446 B
build/block-library/blocks/post-comments-form/style.css 446 B
build/block-library/blocks/post-comments/style-rtl.css 521 B
build/block-library/blocks/post-comments/style.css 521 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 721 B
build/block-library/blocks/post-featured-image/editor.css 721 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 323 B
build/block-library/blocks/post-template/style.css 323 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 80 B
build/block-library/blocks/post-title/style.css 80 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 389 B
build/block-library/blocks/pullquote/style.css 388 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 201 B
build/block-library/blocks/quote/style.css 201 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 397 B
build/block-library/blocks/search/style.css 398 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 233 B
build/block-library/blocks/separator/style.css 233 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 744 B
build/block-library/blocks/site-logo/editor.css 744 B
build/block-library/blocks/site-logo/style-rtl.css 181 B
build/block-library/blocks/site-logo/style.css 181 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.37 kB
build/block-library/blocks/social-links/style.css 1.36 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 226 B
build/block-library/blocks/tag-cloud/style.css 227 B
build/block-library/blocks/template-part/editor-rtl.css 235 B
build/block-library/blocks/template-part/editor.css 235 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 921 B
build/block-library/common.css 919 B
build/block-library/editor-rtl.css 9.89 kB
build/block-library/editor.css 9.9 kB
build/block-library/index.min.js 167 kB
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-library/style-rtl.css 11.3 kB
build/block-library/style.css 11.4 kB
build/block-library/theme-rtl.css 672 B
build/block-library/theme.css 676 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 46.4 kB
build/components/index.min.js 215 kB
build/components/style-rtl.css 15.5 kB
build/components/style.css 15.5 kB
build/core-data/index.min.js 13.9 kB
build/customize-widgets/index.min.js 11.4 kB
build/customize-widgets/style-rtl.css 1.49 kB
build/customize-widgets/style.css 1.49 kB
build/data-controls/index.min.js 663 B
build/data/index.min.js 7.48 kB
build/date/index.min.js 31.9 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.53 kB
build/edit-navigation/index.min.js 16.2 kB
build/edit-navigation/style-rtl.css 3.76 kB
build/edit-navigation/style.css 3.76 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 29.9 kB
build/edit-post/style-rtl.css 7.19 kB
build/edit-post/style.css 7.18 kB
build/edit-site/index.min.js 42.1 kB
build/edit-site/style-rtl.css 7.23 kB
build/edit-site/style.css 7.22 kB
build/edit-widgets/index.min.js 16.7 kB
build/edit-widgets/style-rtl.css 4.17 kB
build/edit-widgets/style.css 4.17 kB
build/editor/index.min.js 38.5 kB
build/editor/style-rtl.css 3.71 kB
build/editor/style.css 3.71 kB
build/element/index.min.js 3.32 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 6.62 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.83 kB
build/keycodes/index.min.js 1.41 kB
build/list-reusable-blocks/index.min.js 1.75 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.94 kB
build/notices/index.min.js 957 B
build/nux/index.min.js 2.12 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.98 kB
build/primitives/index.min.js 949 B
build/priority-queue/index.min.js 611 B
build/react-i18n/index.min.js 704 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.69 kB
build/reusable-blocks/index.min.js 2.24 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.1 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.52 kB
build/token-list/index.min.js 668 B
build/url/index.min.js 1.92 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.18 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.07 kB

compressed-size-action

@gwwar
Copy link
Contributor Author

gwwar commented Feb 24, 2022

As a heads up I'm going to rebase with trunk to see if the E2E clears up

@gwwar gwwar force-pushed the fix/use-drop-zone-state-update-on-unmounted-component branch from 92746c4 to 13e8d97 Compare February 24, 2022 15:54
@gwwar
Copy link
Contributor Author

gwwar commented Feb 24, 2022

I'm investigating the test failures, that'll be really interesting if useFreshRef does show a difference in behavior.

@gwwar
Copy link
Contributor Author

gwwar commented Feb 24, 2022

We do need useFreshRef. Moving to useRef( initialValue ) instead of ref.current = initialValue breaks related E2E tests. I'm going to rollback to my original change and drop a few commits.

@gwwar gwwar force-pushed the fix/use-drop-zone-state-update-on-unmounted-component branch from 13e8d97 to fa14bde Compare February 24, 2022 16:53
Copy link
Member

@dmsnell dmsnell left a comment

Choose a reason for hiding this comment

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

No objections from me. It's a nice targeted patch.

@gwwar
Copy link
Contributor Author

gwwar commented Feb 24, 2022

Thanks for the reviews @dmsnell @sarayourfriend ! I'll try and circle back to the useFreshRef mystery later since I'm curious.

@gwwar gwwar merged commit f833f82 into trunk Feb 24, 2022
@gwwar gwwar deleted the fix/use-drop-zone-state-update-on-unmounted-component branch February 24, 2022 18:52
@github-actions github-actions bot added this to the Gutenberg 12.8 milestone Feb 24, 2022
Comment on lines +222 to +227
onDropRef.current = null;
onDragStartRef.current = null;
onDragEnterRef.current = null;
onDragLeaveRef.current = null;
onDragEndRef.current = null;
onDragOverRef.current = null;
Copy link
Member

@kevin940726 kevin940726 Sep 20, 2022

Choose a reason for hiding this comment

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

I don't think this is the right approach. This creates a problem where the event listeners will no longer be called if the drop zone element has been unmounted and remounted before.

This bug is not easily discoverable because useDropZone is often used in the same render function which assigns the ref to the element.

const ref = useDropZone({ onDragStart });
return <div ref={ref} />

However, if the element getting the ref is somewhere beneath the component's children by passing through different layers of forwardRef, and if one of the children components get remounted at any time, the bug will surface.

const Parent = () => {
  const ref = useDropZone({ onDragStart });
  return <Child ref={ref} />;
};

const Child = forwardRef((props, ref) => {
  return <div ref={ref} />;
});

Since we will not run the render function of Parent again, the event listeners' refs won't get updated to their fresh value, they will continue being null because they have been unmounted before (how ref callbacks or useRefEffect work).

I discovered this bug while working on Popover which unmounts itself (for whatever reason I don't know yet) and in a controlled testing environment.


As for the proper solution to this issue, I can't seem to replicate this warning anymore. It probably relates to the recent update of React to suppress these false positives. Either way, setting the refs here to null doesn't really solve the memory leaks if there's any. Browsers will automatically do GC to clean up those unused listeners anyway. There's likely other reasons behind the warning.

A possible bug might be at line 235?

ownerDocument.addEventListener( 'dragenter', maybeDragStart );

Why do we want to add the listeners again when unmounting? Possibly a typo here (should be removeEventListener)?

Copy link
Contributor

Choose a reason for hiding this comment

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

As for the proper solution to this issue, I can't seem to replicate this warning anymore. It probably relates to the recent update of React to suppress these false positives.

Feel free to open a PR reverting these changes, and we can test to see if the warning that I had flagged is still happening.

Why do we want to add the listeners again when unmounting? Possibly a typo here (should be removeEventListener)?

I think so, it was probably meant to be removeEventListener

Copy link
Member

Choose a reason for hiding this comment

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

Browsers will automatically do GC to clean up those unused listeners anyway.

most of what you share sounds reasonable, but I believe this statement isn't accurate. if we're holding on to a ref in those state values the browser won't be able to GC the listeners because we'll still have a reference to the DOM nodes they are attached to.

probably a new fix is needed if you still see problems, and as @ciampo mentioned, a new PR would be a good place to improve this.

Copy link
Member

Choose a reason for hiding this comment

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

if we're holding on to a ref in those state values the browser won't be able to GC the listeners because we'll still have a reference to the DOM nodes they are attached to.

True! But that falls down to why or when we would still have a reference to those values. The ref callbacks fire themselves with the null value when the underlying element unmounts. And the refs will no longer hold the references when the components unmount. Thus, as long as we don't call useDropZone a bunch of times without passing the returned refs somewhere, React has no reason to still hold the values of those functions.

Feel free to open a PR reverting these changes, and we can test to see if the warning that I had flagged is still happening.

Sure! I'm working on #42722 though, so I'll probably just push a commit there since it's blocking the tests. If it's too much noise in that PR I can then split it into a separate PR ;)

Thanks for the quick responses folks!

Copy link
Member

Choose a reason for hiding this comment

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

The ref callbacks fire themselves with the null value when the underlying element unmounts. And the refs will no longer hold the references when the components unmount.

🤔

okay you got me. I don't see where those ref values are cleared out when they unmount. it looks like useFreshRef will still hold a reference to the old values even if useDropZone gets called with null for their values (after the initial render).

could just be my brain isn't working and I'm missing some hook sequencing, but don't we need some onDropRef.current = assignment somewhere up the stack to remove those references?

Copy link
Member

Choose a reason for hiding this comment

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

As long as we're using useRef, I think React will make sure to dispose those refs after unmounting since they aren't referenced anymore and the engine can then GC them. This assumes that useDropZone and the ref callback are in the same render function (component), or at least unmount at the same time. That is, we don't have to manually clear out the values in refs because React will do it for us (sorta, just think of them as local variables).

const A = () => {
  // The lifecycle of this ref only exists in this component (A).
  // Once A unmounts, ref no longer exists, and the value it holds can then be GCed.
  const ref = useRef();
}

it looks like useFreshRef will still hold a reference to the old values even if useDropZone gets called with null for their values (after the initial render).

Yes. It will still hold the value, but only the latest value, which is what we passed to useDropZone in the first place.

but don't we need some onDropRef.current = assignment somewhere up the stack to remove those references?

This is the part I don't understand 🤔, why do we need to remove those references? They will automatically get removed once the component that calls useDropZone is unmounted. Even if we set those to null at some point, on the next render (if there's any), they will again be set to the latest value (via useFreshRef).

FWIW, these functions will only get called if the event handlers aren't properly canceled/removed. Which means that the memory leak is likely because of the event handlers themselves, not the user-specified callbacks.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for explaining, @kevin940726. I don't have time to build an experiment at this time, but I think I need to see some of this working to fully understand.

It sounds like you're saying we do hold on to the reference to the ref, but it's the .current value of that ref which is actually the DOM node, updated by React to null.

I think that implies if we want access to the DOM node from here we'd have to do something like onDropRef.current.current?

Anyway, I'm just trying to clear my head on this and make sure I understand it all, but it's not important to this PR or your fix. I appreciate you taking the time to help me out.

Copy link
Member

Choose a reason for hiding this comment

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

Oops! Sorry I missed this discussion. @dmsnell do you still have questions/doubts about this? Since this is getting pretty old, I'd be happy to start a new conversation either privately or publicly somewhere! ❤️

Copy link
Member

Choose a reason for hiding this comment

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

It's fine for now @kevin940726 - thanks though. Somewhere in there is a question about the life of the DOM node itself and the life of the ref. If we find that we still have a memory leak we can investigate that avenue.

Have we ever measured if the memory leak this was supposed to fix is actually eliminated after this PR merge?

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

Labels

[Package] Compose /packages/compose [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants