TODO: Adopt React 18 concurrent features now that the upgrade has landed
- Dominant language
- Python
- Stars
- 74.8k
- Forks
- 18.3k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 685
Description
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
- [x] **Enable `` at the root** (`superset-frontend/src/views/index.tsx`) — landed in #39893.
- [ ] **Upgrade `react-redux` v7.2.9 → v8+** — split into sub-issue **#39927** because v8's stricter `useDispatch`/`connect` typing requires a typed `useAppDispatch` migration across many files. Doesn't block `useDeferredValue` work; only blocks `useTransition` adoption (tearing risk under concurrent rendering).
## 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 #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 #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 #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 #39893
2. `useDeferredValue` migration (SQL Lab tree first, core Select after) — does not require v8
3. react-redux v8 typed-dispatch migration — see #39927
4. `startTransition` around native filter apply, with `isPending` indicator — depends on (3)
PRs should reference this issue.
Contributor guide
Assessment
This issue has not been assessed yet.