Skip to content

TODO: Adopt React 18 concurrent features now that the upgrade has landed #39890

Open

Description

@rusackas

Now that #38563 has landed React 18, none of the concurrent-rendering APIs are actually being used yet. This is a tracking issue for adopting the features that move the needle on Superset's perceived performance and forward-compat.

Priorities are ordered roughly by ROI / dependency order — earlier items unblock or de-risk later ones.

Foundation

Concurrent-rendering wins

  • Replace useDebounceValue with useDeferredValue in inputs that filter large client-side lists. useDeferredValue is strictly better than a fixed-delay debounce: deferred updates get interrupted on each keystroke and run at low priority. Targets:
    • SqlLab/components/TableExploreTree/index.tsx:317 (PR perf(sql-lab): debounce schema browser search #39489 introduced the debounce — this is the natural follow-up)
    • explore/components/DatasourcePanel/index.tsx:163 (column search)
    • packages/superset-ui-core/src/components/Select/Select.tsx:387 (used app-wide)
    • explore/components/controls/TextControl/index.tsx:90
    • filters/components/Select/SelectFilterPlugin.tsx:265
    • dashboard/components/nativeFilters/FilterBar/index.tsx:97 (publishDataMask)
  • Wrap heavy cascading Redux dispatches in startTransition so the input that triggered them stays responsive. Highest-impact site: native filter application (changing a filter today blocks the input on chart re-renders). Pair with useTransition's isPending to drive a subtle "applying…" indicator on affected chart cards. Blocked by Migrate to react-redux v8 with a typed AppDispatch / useAppDispatch #39927 — needs typed dispatch + tearing-free store reads.
    • dashboard/components/nativeFilters/FilterBar/index.tsx:268 (updateDataMask)
    • dashboard/components/nativeFilters/FilterBar/index.tsx:455 (saveChartCustomization)
    • explore/components/ExploreViewContainer/index.tsx:468 (triggerQuery after control change)
    • SqlLab/components/TabbedSqlEditors/index.tsx:145 (tab switch)

Lower-priority / opportunistic

  • useId audit — most nanoid usage in the codebase is for persistent data keys (correct, leave alone). The few real DOM-id sites (e.g. DateFilterLabel.tsx:374-375) could move to useId for hygiene but aren't urgent.
  • Suspense coverage — already ~95% on lazy boundaries. Skip unless a specific gap appears.

Notes / risks

  • StrictMode rollout: turning it on may surface failures in component tests that assume effects run exactly once. Plan for a cleanup pass; don't merge alongside other work.
  • Selector hygiene under concurrent rendering: selectors returning a new object reference per call (useSelector(state => ({a, b}))) become a tearing risk. Worth a sweep alongside the react-redux v8 bump (tracked in Migrate to react-redux v8 with a typed AppDispatch / useAppDispatch #39927).
  • Measurement: profile each concurrent-feature PR with React DevTools Profiler before/after. The wins are perceptual; numbers help defend the change.

Suggested PR sequencing

  1. StrictMode + the resulting effect fixes — done in feat(frontend): enable React StrictMode at root #39893
  2. useDeferredValue migration (SQL Lab tree first, core Select after) — does not require v8
  3. react-redux v8 typed-dispatch migration — see Migrate to react-redux v8 with a typed AppDispatch / useAppDispatch #39927
  4. startTransition around native filter apply, with isPending indicator — depends on (3)

PRs should reference this issue.

Activity

  1. changed the title [-]Adopt React 18 concurrent features now that the upgrade has landed[/-] [+]TODO: Adopt React 18 concurrent features now that the upgrade has landed[/+] on May 5, 2026
  2. rusackas commented on May 7, 2026

    @rusackas
    MemberAuthor

    Quick update from a first attempt at the react-redux v8 bump:

    Tried react-redux@8.1.3. v8 tightened useDispatch / connect typing such that thunks no longer auto-resolve against Dispatch<AnyAction>. A spot-check on three SqlLab files surfaced ~50 new TS errors (SqlLabThunkAction<X> is not assignable to AnyAction, etc.). Across the whole codebase that's a multi-hundred-file migration to a typed useAppDispatch hook — too big to bundle into this issue.

    Spun it off into #39927 (Migrate to react-redux v8 with a typed AppDispatch / useAppDispatch). It's now a sub-issue rather than a checklist item here, so it doesn't block the rest of the concurrent-feature work.

    Importantly: useDeferredValue migrations don't depend on the v8 bump — the tearing risk that v8 mitigates only manifests under useTransition. So we can keep shipping useDeferredValue PRs against v7 in the meantime, and useTransition adoption later will block on (or co-land with) the v8 effort.

    Moving on to the useDeferredValue migration starting with SqlLab/components/TableExploreTree/index.tsx (the recently-debounced search).

  3. venkatamandavilli-code commented on May 17, 2026

    @venkatamandavilli-code

    Thanks for reporting this. The behavior seems confusing, especially if the update is saved successfully but the older value still appears afterward.

    At first glance, this feels more like a refresh or metadata persistence issue rather than the actual save failing. It may help to verify whether the API response already contains the updated value before the UI reload happens.

    A hard refresh or testing in another session could also help narrow down whether caching is involved.

    Thanks again for documenting the steps clearly.

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

Metadata

Metadata

Labels

frontend:refactorRelated to refactoring the frontend

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions