Skip to content

improvement(tables): react-doctor safe performance pass#5329

Merged
waleedlatif1 merged 4 commits into
stagingfrom
worktree-tables-react-doctor
Jul 1, 2026
Merged

improvement(tables): react-doctor safe performance pass#5329
waleedlatif1 merged 4 commits into
stagingfrom
worktree-tables-react-doctor

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

What

Installed and ran react-doctor@0.5.8 on the tables module (apps/sim/app/workspace/[workspaceId]/tables) and applied the high-confidence, behavior-preserving performance fixes it surfaced. This is a deliberately conservative pass — no core grid selection/effect logic was refactored.

Changes

  • Lazy ref init (use-workspace-imports.ts) — the import-status useRef(new Map()) allocated and threw away a fresh Map on every render; now lazily initialized once.
  • Map lookup in render path (table-grid/utils.ts) — expandToDisplayColumns called group.outputs.find(...) once per column; now builds an outputs-by-column-name Map once per workflow group.
  • toSorted() (tables.tsx) — replaced [...list].sort() with list.toSorted() (no throwaway copy; ES2023 lib is enabled for apps/sim).
  • Module-scope hoisting — moved the static TITLE_BY_MODE map (workflow-sidebar.tsx) and the pure wheel handler (inline-editors.tsx) out of their components so they aren't rebuilt each render.

Result: react-doctor issues 142 → 137 (Performance 42 → 39, Maintainability 18 → 16).

Deliberately not changed

  • "State synced to a prop inside an effect ×9" and the effect-chain findings in table-grid.tsx — these effects react to async-loaded rows (pagination remapping selection by row id, revealing a search match once its page loads). They are not the copy-a-prop-into-state anti-pattern, and can't move into an event handler since the data arrives from a query. Refactoring them needs live grid verification; the score stays at 37 because of these mostly-false-positive errors.
  • no-barrel-import findings — false positives against this repo's mandated barrel-import convention (sim-imports.md).
  • The setTimeout "needs cleanup" finding — an intentional 6s auto-dismiss that must survive tables re-renders; a naive cleanup would cancel legitimate pending dismissals.

Verification

  • tsc --noEmit clean (0 errors)
  • biome check clean

Apply high-confidence, behavior-preserving perf fixes surfaced by
react-doctor on the tables module:

- Lazy-init the import-status ref so it stops allocating and discarding
  a fresh Map on every render (rerender-lazy-ref-init).
- expandToDisplayColumns: build an outputs-by-column-name Map once per
  workflow group instead of Array.find() per column (js-index-maps).
- Sort the tables list with toSorted() instead of [...list].sort()
  (js-tosorted-immutable; ES2023 lib is enabled for apps/sim).
- Hoist the static TITLE_BY_MODE map and the pure editor wheel handler
  to module scope so they are not rebuilt each render.

Left the effect/selection refactors (state-synced-to-prop, effect
chains) untouched: those effects react to async-loaded rows and are not
the copy-a-prop-into-state anti-pattern; refactoring them needs live
grid verification. Barrel-import findings are false positives against
the repo's mandated barrel-import convention.
@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jul 1, 2026 8:11pm

Request Review

@cursor

cursor Bot commented Jul 1, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Documentation plus small, localized render-path optimizations in tables UI; no API, auth, or grid selection/effect refactors in the diff.

Overview
Adds .claude/rules/sim-react-performance.md and links it from CLAUDE.md, codifying lazy-init object refs, hoisting closure-free values/handlers, Map/Set pre-indexing, copy-then-sort (and avoiding toSorted/toReversed on client), plus that local barrel imports are intentional.

Tables module tweaks (no behavior change): use-workspace-imports lazily allocates the import-status Map ref instead of useRef(new Map()) each render; expandToDisplayColumns builds an outputs-by-column-name Map per workflow group instead of repeated find(); TITLE_BY_MODE is hoisted in workflow-sidebar; inline text editors share a module-level handleEditorWheel for table scroll forwarding.

Reviewed by Cursor Bugbot for commit ba2f6f1. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR applies a conservative React performance pass to the tables UI. The main changes are:

  • Lazy initialization for the import-status ref map.
  • First-match-preserving Map lookup for workflow output columns.
  • Module-scope hoisting for static titles and a wheel handler.
  • Guidance updates for safe React render-performance patterns.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/utils.ts The workflow output lookup now uses a prebuilt map while preserving the old first-match behavior.
apps/sim/app/workspace/[workspaceId]/tables/components/import-progress-menu/use-workspace-imports.ts The import status map is now initialized lazily without changing the status transition tracking path.
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx The inline editor wheel handler was moved to module scope with the same event behavior.
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/workflow-sidebar/workflow-sidebar.tsx The workflow sidebar title lookup was moved to module scope with the same mode mapping.
.claude/rules/sim-react-performance.md The new rule document records safe React render-performance patterns for future changes.
CLAUDE.md The main contributor guide now links to the React performance guidance.

Reviews (3): Last reviewed commit: "refactor(tables): tidy lazy ref init and..." | Re-trigger Greptile

Comment thread apps/sim/app/workspace/[workspaceId]/tables/tables.tsx Outdated
… perf idioms

- expandToDisplayColumns: build the outputs-by-column-name index with an
  explicit first-write-wins loop so it is provably identical to the prior
  Array.find() on the (schema-precluded) duplicate-columnName case, not
  last-wins as new Map(entries) would be.
- Add .claude/rules/sim-react-performance.md capturing the behavior-
  preserving render-perf idioms applied here (lazy object refs, module-
  scope hoisting, Map/Set pre-indexing, immutable array methods with the
  ES2022/ES2023 lib caveat, local-barrel false-positive note), and point
  to it from CLAUDE.md.
…port

Array.prototype.toSorted is ES2023 runtime; SWC does not polyfill it and
the default browserslist still includes browsers without it (iOS 15
Safari), so the tables page would crash there. [...result].sort() is
non-mutating (sorts a copy, never touches the React Query cache array)
and works everywhere; the perf delta is negligible. Correct the
sim-react-performance rule doc to reflect that tsconfig lib only affects
type-checking, not runtime availability.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit dc4510c. Configure here.

- use-workspace-imports: lazy-init the status Map at its point of use in
  the effect ((ref.current ??= new Map())) instead of mutating the ref
  during render with a separate in-effect fallback. The ref is only read
  in the effect, so this removes the render-phase write and the dead
  '?? new Map()' branch while keeping the identical persistent Map.
- CLAUDE.md: fix the render-performance pointer so it matches the rule
  doc — toSorted/toReversed are unsafe on client render paths (SWC does
  not polyfill prototype methods), not merely an ES2022/ES2023 lib note.
@waleedlatif1 waleedlatif1 merged commit 6715354 into staging Jul 1, 2026
9 of 10 checks passed
@waleedlatif1 waleedlatif1 deleted the worktree-tables-react-doctor branch July 1, 2026 20:11
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ba2f6f1. Configure here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant