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

Maximum update depth exceeded #30162

Open
3 tasks done
ohitsdoh opened this issue Sep 5, 2024 · 2 comments
Open
3 tasks done

Maximum update depth exceeded #30162

ohitsdoh opened this issue Sep 5, 2024 · 2 comments
Labels
dashboard:native-filters Related to the native filters of the Dashboard dashboard:performance Related to Dashboard performance

Comments

@ohitsdoh
Copy link

ohitsdoh commented Sep 5, 2024

Bug description

Periodically getting this issue in dashboard filters, particularly when there are a lot of filters

How to reproduce the bug

Load a dashboard with a lot of filters

Screenshots/recordings

image image

Superset version

master / latest-dev

Python version

3.9

Node version

16

Browser

Chrome

Additional context

Error: Minified React error #185; visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
at uc (react-dom.production.min.js:230:46)
at gi (react-dom.production.min.js:163:512)
at useChildElementTruncation.ts:99:9
at ul (react-dom.production.min.js:211:320)
at sl (react-dom.production.min.js:212:65)
at Cc (react-dom.production.min.js:255:229)
at t.unstable_runWithPriority (scheduler.production.min.js:19:467)
at Ka (react-dom.production.min.js:122:325)
at Pc (react-dom.production.min.js:248:370)
at mc (react-dom.production.min.js:239:376)
ol @ react-dom.production.min.js:209
Show 1 more frame
Show less

Checklist

  • I have searched Superset docs and Slack and didn't find a solution to my problem.
  • I have searched the GitHub issue tracker and didn't find a similar bug report.
  • I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
@dosubot dosubot bot added the dashboard:performance Related to Dashboard performance label Sep 5, 2024
Copy link

dosubot bot commented Sep 5, 2024

Hey @ohitsdoh! 👋 I'm here to help you with bug fixes, answer questions, and guide you on becoming a contributor. Let's squash those bugs together!

To resolve the "Maximum update depth exceeded" error in Apache Superset when loading a dashboard with many filters, you can optimize the useEffect hooks to depend on more granular information instead of big objects that require deep comparison. This can help prevent unnecessary re-renders and infinite loops.

Here's a revised version of the useEffect hook with more granular dependencies:

useEffect(() => {
  if (!inViewFirstTime) {
    return;
  }

  const newFormData = getFormData({
    ...filter,
    datasetId,
    dependencies,
    groupby,
    adhoc_filters,
    time_range,
    dashboardId,
  });

  const filterOwnState = filter.dataMask?.ownState || {};

  const customizer = (
    objValue: Partial<QueryFormData>,
    othValue: Partial<QueryFormData>,
    key: string,
  ) => (key === 'url_params' ? true : undefined);

  const formDataChanged = !isEqualWith(formData, newFormData, customizer);
  const ownStateChanged = !isEqual(ownState, filterOwnState);

  if (!isRefreshing && (formDataChanged || ownStateChanged || shouldRefresh)) {
    setFormData(newFormData);
    setOwnState(filterOwnState);

    if (!hasDataSource) {
      return;
    }

    setIsRefreshing(true);

    getChartDataRequest({
      formData: newFormData,
      force: shouldRefresh,
      ownState: filterOwnState,
    })
      .then(({ response, json }) => {
        if (isFeatureEnabled(FeatureFlag.GlobalAsyncQueries)) {
          const result = 'result' in json ? json.result[0] : json;

          if (response.status === 200) {
            setState([result]);
            handleFilterLoadFinish();
          } else if (response.status === 202) {
            waitForAsyncData(result)
              .then((asyncResult: ChartDataResponseResult[]) => {
                setState(asyncResult);
                handleFilterLoadFinish();
              })
              .catch((error: Response) => {
                getClientErrorObject(error).then(clientErrorObject => {
                  setError(clientErrorObject);
                  handleFilterLoadFinish();
                });
              });
          } else {
            throw new Error(
              `Received unexpected response status (${response.status}) while fetching chart data`,
            );
          }
        } else {
          setState(json.result);
          setError(undefined);
          handleFilterLoadFinish();
        }
      })
      .catch((error: Response) => {
        getClientErrorObject(error).then(clientErrorObject => {
          setError(clientErrorObject);
          handleFilterLoadFinish();
        });
      });
  }
}, [
  inViewFirstTime,
  dependencies.length, // Use length instead of the entire array
  datasetId,
  groupby,
  adhoc_filters.length, // Use length instead of the entire array
  time_range,
  dashboardId,
  handleFilterLoadFinish,
  hasDataSource,
  isRefreshing,
  shouldRefresh,
]);

By using more specific dependencies like dependencies.length and adhoc_filters.length, you can reduce the likelihood of unnecessary re-renders and avoid the "Maximum update depth exceeded" error [1].

Additionally, ensure that the applyCharts method in the Dashboard component is optimized to avoid unnecessary updates. The applyCharts method should only trigger updates when there are actual changes in the filters or charts. This can be achieved by comparing the current and previous states of filters and charts using utility functions like areObjectsEqual.

applyCharts() {
  const { hasUnsavedChanges, editMode } = this.props.dashboardState;

  const { appliedFilters, appliedOwnDataCharts } = this;
  const { activeFilters, ownDataCharts, chartConfiguration } = this.props;
  if (
    isFeatureEnabled(FeatureFlag.DashboardCrossFilters) &&
    !chartConfiguration
  ) {
    // For a first loading we need to wait for cross filters charts data loaded to get all active filters
    // for correct comparing of filters to avoid unnecessary requests
    return;
  }

  if (
    !editMode &&
    (!areObjectsEqual(appliedOwnDataCharts, ownDataCharts, {
      ignoreUndefined: true,
    }) ||
      !areObjectsEqual(appliedFilters, activeFilters, {
        ignoreUndefined: true,
      }))
  ) {
    this.applyFilters();
  }

  if (hasUnsavedChanges) {
    Dashboard.onBeforeUnload(true);
  } else {
    Dashboard.onBeforeUnload(false);
  }
}

By ensuring that applyCharts only triggers updates when necessary, you can further reduce the risk of encountering the "Maximum update depth exceeded" error [2].

To continue talking to Dosu, mention @dosu.

@rusackas rusackas added the dashboard:native-filters Related to the native filters of the Dashboard label Sep 5, 2024
@rusackas
Copy link
Member

rusackas commented Sep 5, 2024

How many is a lot? Can you reproduce this somehow with example dashboards / datasets?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dashboard:native-filters Related to the native filters of the Dashboard dashboard:performance Related to Dashboard performance
Projects
None yet
Development

No branches or pull requests

2 participants