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

refactor: useEffectEvent for efficient deps #23871

Merged
merged 4 commits into from
May 3, 2023

Conversation

justinpark
Copy link
Member

@justinpark justinpark commented Apr 28, 2023

SUMMARY

We often to update(add) the useEffect dependencies to fix the dependency warnings (i.e. #22974)
This work has potential performance degrade issue.

For example, #22974 updated the following useEffect dependancies.

useEffect(() => {
// We need to measure the height of the sql editor post render to figure the height of
// the south pane so it gets rendered properly
setHeight(getSqlEditorHeight());
if (!database || isEmpty(database)) {
setShowEmptyState(true);
}
window.addEventListener('resize', handleWindowResizeWithThrottle);
window.addEventListener('beforeunload', onBeforeUnload);
return () => {
window.removeEventListener('resize', handleWindowResizeWithThrottle);
window.removeEventListener('beforeunload', onBeforeUnload);
};
}, [database, handleWindowResizeWithThrottle, onBeforeUnload]);

This means setHeight and window event allocation can be triggered anytime handleWindowResizeWithThrottle/onBeforeUnload or/and updated.

The problem is onBeforeUnload also has dependancies by useCallback

const onBeforeUnload = useCallback(
event => {
if (
database?.extra_json?.cancel_query_on_windows_unload &&
latestQuery?.state === 'running'
) {
event.preventDefault();
stopQuery();
}
},
[
database?.extra_json?.cancel_query_on_windows_unload,
latestQuery?.state,
stopQuery,
],
);

So whenever database is updated or latestQuery state updated, the above useEffect triggers the additional setHeight(which triggers re-rendering) and new event allocation (no memory leaked but unnecessary addEventListener/removeEventListener operation triggered)

This is common issue on react useEffect usage, so there's an official solution (useEffectEvent) is introduced.
For more detail, please check the blog link /w video clip or official proposal document

FYI: currently eslint rule of exhaustive-deps related to useEffectEvent is under experimental, this commit uses use-event-callback to avoid the warning

In addition to introduce the useEffectEvent, this commit also tune up L365-L380 to avoid the unnecessary setHeight triggered during database is updated.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A

TESTING INSTRUCTIONS

Resize sqllab editor to verify the query panel height adjusted accordingly.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@pull-request-size pull-request-size bot added size/M and removed size/L labels Apr 29, 2023
@codecov
Copy link

codecov bot commented Apr 29, 2023

Codecov Report

Merging #23871 (bd6ac8a) into master (594d3e0) will decrease coverage by 0.03%.
The diff coverage is 66.66%.

❗ Current head bd6ac8a differs from pull request most recent head 668d4e5. Consider uploading reports for the commit 668d4e5 to get more accurate results

@@            Coverage Diff             @@
##           master   #23871      +/-   ##
==========================================
- Coverage   68.11%   68.08%   -0.03%     
==========================================
  Files        1938     1941       +3     
  Lines       74972    75020      +48     
  Branches     8141     8154      +13     
==========================================
+ Hits        51067    51079      +12     
- Misses      21826    21858      +32     
- Partials     2079     2083       +4     
Flag Coverage Δ
javascript 54.46% <48.00%> (-0.02%) ⬇️
mysql ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...s/legacy-plugin-chart-calendar/src/controlPanel.ts 50.00% <ø> (ø)
...rts/src/BigNumber/BigNumberTotal/transformProps.ts 0.00% <0.00%> (ø)
...lugin-chart-echarts/src/BigNumber/BigNumberViz.tsx 0.00% <0.00%> (ø)
...set-frontend/src/components/Select/AsyncSelect.tsx 88.46% <ø> (ø)
superset-frontend/src/components/Select/Select.tsx 90.41% <ø> (ø)
...onalFormattingControl/FormattingPopoverContent.tsx 51.35% <ø> (ø)
superset-frontend/src/preamble.ts 0.00% <0.00%> (ø)
superset-frontend/src/setup/setupFormatters.ts 0.00% <ø> (ø)
superset-frontend/src/types/bootstrapTypes.ts 100.00% <ø> (ø)
superset/cli/native_filters.py 0.00% <ø> (ø)
... and 16 more

... and 6 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@@ -354,39 +355,28 @@ const SqlEditor = ({
return base;
}, [dispatch, queryEditor.sql, startQuery, stopQuery]);

const handleWindowResize = useCallback(() => {
const handleWindowResize = useEffectEvent(() => {
setHeight(getSqlEditorHeight());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
setHeight(getSqlEditorHeight());
setHeight(height);

Copy link
Member Author

Choose a reason for hiding this comment

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

In this approach, this doesn't need to wrap with useEffectEvent since no references needed other than setHeight.
Let me clean up with setHeight then.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, that's right. I didn't notice it was a useState 👍🏼

@@ -354,39 +355,28 @@ const SqlEditor = ({
return base;
}, [dispatch, queryEditor.sql, startQuery, stopQuery]);

const handleWindowResize = useCallback(() => {
const handleWindowResize = useEffectEvent(() => {
Copy link
Member

Choose a reason for hiding this comment

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

You should pass the height to the effect event. Check the Notes here.

Suggested change
const handleWindowResize = useEffectEvent(() => {
const handleWindowResize = useEffectEvent(height => {

Copy link
Member Author

Choose a reason for hiding this comment

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

removed handleWindowResize since no longer needed

@michael-s-molina
Copy link
Member

This will be indeed a nice addition to React. Looking forward to it.

Copy link
Member

@michael-s-molina michael-s-molina left a comment

Choose a reason for hiding this comment

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

LGTM

@justinpark justinpark merged commit 842659d into apache:master May 3, 2023
@mistercrunch mistercrunch added 🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels 🚢 3.0.0 labels Mar 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels size/M 🚢 3.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants