Conversation
Also: change the logic a bit -> the whole component is recreated on data frame change. It's simpler (before we were only recreating part of the providers, but it was more complex and ended in rerendering everything).
There was a problem hiding this comment.
Pull request overview
This PR refactors HighTable to separate internal state management from DOM rendering by moving dataframe-derived state into dedicated contexts (DataVersionContext, NumRowsContext) via a new DataProvider, reducing prop-drilling and aiming to limit unnecessary re-renders/unmounts.
Changes:
- Replace the former
useDatahook approach with a newDataProvider+DataContext(version/numRows via context). - Update providers/components (Selection/Scroll/CellNavigation/Slice/Wrapper) to consume
numRows/versionfrom context instead of props. - Restructure
HighTableintoStateandDOMsubtrees and add tests around remounting and the new provider behavior.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/providers/SelectionProvider.test.tsx | Adjusts tests to provide numRows via NumRowsContext.Provider. |
| test/providers/DataProvider.test.tsx | Adds new test coverage for DataProvider version/numRows behavior. |
| test/providers/CellNavigationProvider.test.tsx | Adjusts tests to provide numRows via NumRowsContext.Provider. |
| test/hooks/useData.test.ts | Removes tests for the deleted useData hook. |
| src/providers/SelectionProvider.tsx | Switches from numRows prop to useNumRows() context consumption. |
| src/providers/ScrollProvider.tsx | Switches from numRows prop to useNumRows() context consumption. |
| src/providers/DataProvider.tsx | Introduces DataProvider that publishes version and numRows via context. |
| src/providers/CellNavigationProvider.tsx | Switches from numRows prop to useNumRows() context consumption. |
| src/contexts/DataContext.ts | Adds DataVersionContext/NumRowsContext and hooks. |
| src/components/HighTable/Wrapper.tsx | Switches from numRows prop to useNumRows() context consumption. |
| src/components/HighTable/Slice.tsx | Switches from numRows/version props to useNumRows()/useDataVersion(). |
| src/components/HighTable/HighTable.tsx | Splits State/DOM and attempts to remount state when dataframe instance changes. |
| src/components/HighTable/HighTable.test.tsx | Adds coverage to validate remount behavior when dataframe instance changes. |
Comments suppressed due to low confidence (2)
src/providers/DataProvider.tsx:15
- The JSDoc for
DataProvidersays it “Handles the viewport size (width and height) state”, but this provider actually managesversion/numRowsderived from the dataframe. Please update the comment to reflect the actual responsibility to avoid misleading future changes.
src/providers/DataProvider.tsx:42 DataProviderinitializesnumRowsfrom the initialdataprop, but when a new dataframe instance is passed, neithernumRowsnorversionare reset/synchronized to the newdatavalue. Because the effect only attaches listeners, consumers can observe stalenumRows/versionafter adataprop change. Consider resettingversionto 0 andnumRowstodata.numRowswhendatachanges (e.g., inside the[data]effect).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…tory to check if it works as expected
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
src/providers/DataProvider.tsx:15
- DataProvider’s JSDoc appears to be copied from the viewport-size provider (it describes viewport width/height), but this component actually tracks
versionandnumRowsfrom the dataframe and exposes them viaDataVersionContext/NumRowsContext. Please update the docstring to reflect the actual behavior to avoid misleading future changes.
src/providers/DataProvider.tsx:25 DataProviderdoesn’t reset/sync its internalversionandnumRowsstate when thedataprop changes to a different dataframe instance (it only swaps event listeners). If a parent rerenders this provider with a newdata, consumers can keep seeing the oldnumRows/versionuntil events fire. Consider explicitly resetting state in auseEffectkeyed ondata(e.g., setnumRowstodata.numRowsand resetversion), or document/enforce thatDataProvidermust be remounted on data changes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
src/providers/DataProvider.tsx:15
- The JSDoc above
DataProviderdescribes viewport size state/contexts, but this provider actually tracksversionandnumRowsfrom the dataframe and exposes them viaDataVersionContext/NumRowsContext. Please update the comment so it matches the current behavior to avoid misleading future changes.
src/providers/DataProvider.tsx:42 - When the
dataprop changes, this effect re-wires event listeners but the provider state (version,numRows) is not reset to match the new dataframe instance. That can leave consumers seeing stale values until the new dataframe emits events. Consider resettingversion/numRowswhendatachanges (e.g., inside this effect before registering listeners, or in a separateuseEffectkeyed ondata).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
src/providers/DataProvider.tsx:19
- DataProvider doesn’t reset
version/numRowswhen thedataprop changes; it only re-subscribes to the new eventTarget. If a different dataframe instance is passed without remounting this component,numRowscan stay stuck on the previous dataframe until anumrowschangeevent fires (andversionwon’t reset), so the provided context becomes incorrect. Consider resetting state in auseEffectwhendatachanges, or explicitly require/ensure DataProvider is keyed bydata.
src/providers/DataProvider.tsx:15 - The docblock above
DataProviderappears to describe viewport size state, but this provider manages dataframe-derived state (versionandnumRows) and exposes them via DataVersionContext/NumRowsContext. Please update the comment to match the actual responsibility to avoid misleading maintainers.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/providers/DataProvider.tsx:23
DataProviderkeepsversionandnumRowsin local state but doesn’t reset/synchronize them when thedataprop changes. BecauseuseState(data.numRows)only applies on first mount, rerenderingDataProviderwith a different dataframe instance will continue to expose the previous dataframe’snumRows/versionuntil the new dataframe emits events. Consider updating state in response todatachanges (e.g., setnumRowsfrom the new dataframe immediately and resetversion), or explicitly document/encode the requirement that the component is always remounted on data changes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…data change. Also restore test
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
See #449
The internal state is handled with contexts (even if it creates some sort of "Providers hell" - still manageable, no need for an external state library).
Now, the state and the DOM are clearly separated.
Replace useData hook with a DataProvider, to reduce the number of rerenders.
Everything (state and DOM) is recreated when a new data frame is passed. It was already the case before. An improvement might be to adapt the internal state to the new data frame, but I'm not sure we need to add this complexity, if changing the data prop is not a common action. I'll work on it in a future PR.
Note that the "DOM" component still has some internal state, it's not stateless, but it's a cleaner way to separate the global state from the elements.
Note that (even if I don't really understand what FPS exactly measures in React Scan), the FPS are increasing. Beware: it's not a scientific experiment, take with care, and see if you reproduce.
before:
Screencast.From.2026-03-03.16-23-05.mp4
after:
Screencast.From.2026-03-03.16-22-34.mp4
(I don't reproduce anymore :) )