-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Components: refactor Sandbox
to pass exhaustive-deps
#44378
Conversation
Size Change: -3 B (0%) Total Size: 1.26 MB
ℹ️ View Unchanged
|
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.
Thank you for working on this, @chad1008
Unfortunately I think that most of the suggested changes would make the Sandbox component behave in a different way to how it was intended to. In order to keep using useEffect
s like today and respect the exhaustive deps rule, we'd probably need to refactor the code heavily (and probably rely of refs holding the previous value of some props).
Probably the best thing to do here is to add eslint-ignore comments, as I'm afraid that a proper fix could be tricky to write, tricky to test and could take some time to apply.
Also cc'ing @ellatrix who mostly worked on this component, in case she has any other suggestions on how to rewrite this component respecting the exhaustive-deps
rule.
@@ -215,23 +221,21 @@ export default function Sandbox( { | |||
ref.current.addEventListener( 'load', tryNoForceSandbox, false ); | |||
defaultView.addEventListener( 'message', checkMessageForResize ); | |||
|
|||
const iframeRef = ref.current; |
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.
We should probably declare this variable a few lines up, and use it also instead for the ref.current.addEventListener
call?
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.
diff --git a/packages/components/src/sandbox/index.js b/packages/components/src/sandbox/index.js
index 6bf9669613..67929c6e4e 100644
--- a/packages/components/src/sandbox/index.js
+++ b/packages/components/src/sandbox/index.js
@@ -205,22 +205,19 @@ export default function Sandbox( {
setHeight( data.height );
}
- const { ownerDocument } = ref.current;
+ const iframe = ref.current;
+ const { ownerDocument } = iframe;
const { defaultView } = ownerDocument;
// This used to be registered using <iframe onLoad={} />, but it made the iframe blank
// after reordering the containing block. See these two issues for more details:
// https://github.com/WordPress/gutenberg/issues/6146
// https://github.com/facebook/react/issues/18752
- ref.current.addEventListener( 'load', tryNoForceSandbox, false );
+ iframe.addEventListener( 'load', tryNoForceSandbox, false );
defaultView.addEventListener( 'message', checkMessageForResize );
return () => {
- ref.current?.removeEventListener(
- 'load',
- tryNoForceSandbox,
- false
- );
+ iframe?.removeEventListener( 'load', tryNoForceSandbox, false );
defaultView.addEventListener( 'message', checkMessageForResize );
};
}, [] );
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.
Good point! I'll hold off on this for now, since we're going with ignore-rule comments instead for the time being, but thank you for sharing it with me!
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.
...actually, scratch that. I've included this change in PR, as it isn't subject to the same complications as the useEffect
dependencies.
}, [ trySandbox ] ); | ||
|
||
useEffect( () => { | ||
trySandbox(); | ||
}, [ title, styles, scripts ] ); | ||
}, [ trySandbox ] ); | ||
|
||
useEffect( () => { | ||
trySandbox( true ); | ||
}, [ html, type ] ); | ||
}, [ trySandbox ] ); |
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.
I'm afraid that the refactor around trySandbox
doesn't make much sense — it looks like the author's original intent was to pass true
to the trySandbox
call only when html
and type
changed — with the current changes in this PR, trySandbox
would be called with both undefined
and true
everytime its value changes.
defaultView.addEventListener( 'message', checkMessageForResize ); | ||
}; | ||
}, [] ); | ||
}, [ trySandbox ] ); |
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 useEffect
was supposed to run only when the component mounts, but with the changes from this PR it will run every time trySandbox
changes — i.e any time any of its dependencies change.
Thanks for the feedback Marco - this one was definitely harder to parse/test, so you're probably right about simply ignoring for now, and refactoring later. I'll update the PR to reverse the proposed changes and apply some |
…ame Ref declaration
1967c7a
to
eec8709
Compare
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.
LGTM for now. We can always come back to this and attempt to rewrite this component, likely in a way that avoids a few useEffect
calls
What?
Updates the
Sandbox
component to satisfy theexhaustive-deps
eslint ruleWhy?
Part of the effort in #41166 to apply
exhuastive-deps
to the Components packageHow?
ref.current
was originally called in theuseEffect
cleanup function, but it's possible/likely that value will change before the cleanup is run. Because the ref points to a node rendered by React, the linter recommends copying the ref value to a variable inside the effect, and then referencing that variable in the cleanup function.trySandbox
was a missed dependency for several effects, so it's now wrapped in auseCallback
.The last two
useEffects
previously had some of the component's props as dependencies, even though the don't actually appear in the effect. Now that those props will causetrySandbox
to be redeclared, andtrySandbox
is a dependency of those effects, I've removed those old deps to clean up the arrays.Last but not least, an ignore comment has been added to the one native file that was throwing a warning so this can be refactored by the native team.
Testing Instructions
npx eslint --rule 'react-hooks/exhaustive-deps: warn' packages/components/src/sandbox