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

fix(sqllab): avoid unexpected re-rendering on DatabaseSelector #21316

Conversation

justinpark
Copy link
Member

@justinpark justinpark commented Sep 2, 2022

SUMMARY

Reopen: #21141

Since DatabaseSelector component has an unnecessary key, DatabaseSelector will be re-mounted rather than update whenever currentDatabase object is updated. This causes the unexpected duplicate database list api request.
This commit removes this key so will skip unnecessary re-rendering and data fetching.
It also fixes the logic for currentDb that directly transform from db instead of useState. (This resolves the issue for #21174)

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Before:

fix--unnecessary-dabaseselector-rerendering

After:

Screen Shot 2022-08-19 at 2 50 12 PM

TESTING INSTRUCTIONS

go to Sql Editor and check the network list

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

cc: @ktmud

@codecov
Copy link

codecov bot commented Sep 3, 2022

Codecov Report

Merging #21316 (2b1abdc) into master (d67b046) will increase coverage by 0.00%.
The diff coverage is 88.88%.

@@           Coverage Diff           @@
##           master   #21316   +/-   ##
=======================================
  Coverage   66.66%   66.66%           
=======================================
  Files        1794     1794           
  Lines       68639    68643    +4     
  Branches     7300     7301    +1     
=======================================
+ Hits        45755    45764    +9     
+ Misses      21014    21011    -3     
+ Partials     1870     1868    -2     
Flag Coverage Δ
javascript 52.82% <88.88%> (+0.01%) ⬆️

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

Impacted Files Coverage Δ
...et-frontend/src/components/TableSelector/index.tsx 80.00% <ø> (ø)
...frontend/src/components/DatabaseSelector/index.tsx 93.93% <80.00%> (-1.30%) ⬇️
...set-frontend/src/components/Select/AsyncSelect.tsx 87.97% <100.00%> (+3.36%) ⬆️

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

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.

Thanks for the PR @justinpark. Is there a reason for removing AsyncSelect useEffect dependencies?

@pull-request-size pull-request-size bot added size/M and removed size/S labels Sep 15, 2022
@justinpark justinpark force-pushed the fix--sqllab-unexpected-database-selector-rerendering branch from b777a0d to 243ba07 Compare September 15, 2022 20:42
@justinpark
Copy link
Member Author

Is there a reason for removing AsyncSelect useEffect dependencies?

@michael-s-molina Because fetchPage kept changing while initializing due to the object dependencies, useEffect has been triggered multiple times which causes unnecessary fetchPage calls.

I made a change to reduce and fix the dependencies for fetchPage and rollback this useEffect dependencies.

@michael-s-molina
Copy link
Member

Is there a reason for removing AsyncSelect useEffect dependencies?

@michael-s-molina Because fetchPage kept changing while initializing due to the object dependencies, useEffect has been triggered multiple times which causes unnecessary fetchPage calls.

I made a change to reduce and fix the dependencies for fetchPage and rollback this useEffect dependencies.

@justinpark We can't add the responsibility of the immutability of the options to the Select component because there are some cases where we want to fire the requests again when the function changes. To fix your problem, you just need to make sure options only change when you in fact want them to. This is generally accomplished by the use of useMemo or useCallback on the parent component depending on the case.

@justinpark justinpark force-pushed the fix--sqllab-unexpected-database-selector-rerendering branch from 6685af6 to b5242ea Compare September 16, 2022 21:04
@justinpark
Copy link
Member Author

justinpark commented Sep 16, 2022

Is there a reason for removing AsyncSelect useEffect dependencies?

michael-s-molina Because fetchPage kept changing while initializing due to the object dependencies, useEffect has been triggered multiple times which causes unnecessary fetchPage calls.
I made a change to reduce and fix the dependencies for fetchPage and rollback this useEffect dependencies.

justinpark We can't add the responsibility of the immutability of the options to the Select component because there are some cases where we want to fire the requests again when the function changes. To fix your problem, you just need to make sure options only change when you in fact want them to. This is generally accomplished by the use of useMemo or useCallback on the parent component depending on the case.

Okay. @michael-s-molina I finally cleaned up the main cause.

  1. I removed the selectValue dependency on sortSelectedFirst and useRef instead because this is the major reason that triggers fetchPage multiple times. mergeData function will be updated whenever selectedValue is updated due to the dependency of sortSelectedFirst.

const sortSelectedFirst = useCallback(
(a: AntdLabeledValue, b: AntdLabeledValue) =>
sortSelectedFirstHelper(a, b, selectValue),
[selectValue],
);

const sortComparatorForNoSearch = useCallback(
(a: AntdLabeledValue, b: AntdLabeledValue) =>
sortComparatorForNoSearchHelper(
a,
b,
sortSelectedFirst,
sortComparator,
),
[sortComparator, sortSelectedFirst],
);

const mergeData = useCallback(
(data: SelectOptionsType) => {
let mergedData: SelectOptionsType = [];
if (data && Array.isArray(data) && data.length) {
// unique option values should always be case sensitive so don't lowercase
const dataValues = new Set(data.map(opt => opt.value));
// merges with existing and creates unique options
setSelectOptions(prevOptions => {
mergedData = prevOptions
.filter(previousOption => !dataValues.has(previousOption.value))
.concat(data)
.sort(sortComparatorForNoSearch);
return mergedData;
});
}
return mergedData;
},
[sortComparatorForNoSearch],

[
allValuesLoaded,
fetchOnlyOnSearch,
mergeData,
internalOnError,
options,
pageSize,
value,
],

useEffect(() => {
if (loadingEnabled && allowFetch) {
// trigger fetch every time inputValue changes
if (inputValue) {
debouncedFetchPage(inputValue, 0);
} else {
fetchPage('', 0);
}
}
}, [loadingEnabled, fetchPage, allowFetch, inputValue, debouncedFetchPage]);

  1. I fixed the invalid checking for setAllValuesLoaded. (Since allValuesLoaded should check whether the current request is for the full list or not, it should check the search rather than value)

  2. When removes the key in DatabaseSelector, its initial database selection has gone. (fix(sqllab): reverts #21141 #21174) The issue is caused by the missing currentDb mapping when db prop is updated. I added the useEffect logic to handle this issue.

const [currentDb, setCurrentDb] = useState<DatabaseValue | undefined>(
db
? {
label: (
<SelectLabel backend={db.backend} databaseName={db.database_name} />
),
value: db.id,
...db,
}
: undefined,

  1. Lastly I found the same useEffect logic on AsyncSelect so removed one

}, [initialOptions]);
useEffect(() => {
setSelectValue(value);
}, [value]);

);
useEffect(() => {
setSelectValue(value);
}, [value]);

@justinpark justinpark force-pushed the fix--sqllab-unexpected-database-selector-rerendering branch from f4c2282 to 2b1abdc Compare September 23, 2022 16:07
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. Thanks for the fixes @justinpark!

@michael-s-molina michael-s-molina merged commit e2b77a7 into apache:master Sep 23, 2022
@mistercrunch mistercrunch added 🏷️ bot A label used by `supersetbot` to keep track of which PR where auto-tagged with release labels 🚢 2.1.0 and removed 🚢 2.1.3 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 🚢 2.1.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants