fix: table data not refreshing after mo.output.replace() when first-page data is unchanged#8066
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…-page data is unchanged Closes #8023 ### Problem When a `mo.ui.table` is replaced via `mo.output.replace()` with updated data, the table may show stale data if the unsorted first page hasn't changed (e.g., only a row on page 2 was modified). When `mo.output.replace(table)` creates a new table instance: 1. React reuses the existing DOM nodes (same element type/position) 2. `<marimo-ui-element>`'s `attributeChangedCallback` fires and calls `reset()` on the child plugin 3. The React component stays **mounted** — `useState` values (like sorting) persist 4. `functionMethods` (containing `search`) is memoized on `[plugin.functions, hostElement]` — both remain stable across resets 5. `props.data` is a JSON **string** — strings with the same content are `Object.is`-equal in JavaScript 6. Therefore **all** `useAsyncData` deps remain the same, the effect doesn't re-fire, and stale data from the previous table instance persists ### Fix Added a `resetNonce` state counter to `PluginSlotInternal` that increments on every `reset()` call. This nonce is included in the `functionMethods` `useMemo` dependency array, which causes the `search` function reference to change when the table instance changes. `useAsyncData` then sees the new dependency and re-fires its fetch effect, pulling fresh data from the new table.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where table data would not refresh after mo.output.replace() when the first page data remained unchanged. The root cause was that memoized function references in React weren't being invalidated when a new table instance was created, leading to stale data being displayed.
Changes:
- Added a
resetNoncecounter toPluginSlotInternalthat increments onreset()to invalidate memoized function references - Included smoke test reproducing the original issue (#8023)
- Added comprehensive test coverage for the fix in both DataTablePlugin and DataTable components
- Minor style improvements: TypeScript array syntax modernization and if-else-if to switch statement refactoring
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| marimo/_smoke_tests/issues/8023_stale_table.py | Smoke test reproducing the issue from #8023 |
| frontend/src/utils/mime-types.ts | Modernized TypeScript array syntax from Array<T> to T[] |
| frontend/src/utils/tests/mime-types.test.ts | Updated test syntax to match mime-types.ts changes |
| frontend/src/plugins/impl/tests/DataTablePlugin.test.tsx | Added test verifying search function reference changes trigger data refetch |
| frontend/src/plugins/core/registerReactComponent.tsx | Core fix: Added resetNonce state to invalidate memoized functionMethods on reset |
| frontend/src/core/MarimoApp.tsx | Refactored if-else chain to switch statement for readability |
| frontend/src/components/data-table/tests/data-table.test.tsx | Added test simulating the bug scenario with manual sorting and pagination |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Light2Dark
approved these changes
Feb 3, 2026
|
🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.19.8-dev9 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #8023
Problem
When a
mo.ui.tableis replaced viamo.output.replace()with updated data,the table may show stale data if the unsorted first page hasn't changed
(e.g., only a row on page 2 was modified).
When
mo.output.replace(table)creates a new table instance:<marimo-ui-element>'sattributeChangedCallbackfires and callsreset()on the child plugin
useStatevalues (like sorting) persistfunctionMethods(containingsearch) is memoized on[plugin.functions, hostElement]— both remain stable across resetsprops.datais a JSON string — strings with the same content areObject.is-equal in JavaScriptuseAsyncDatadeps remain the same, the effect doesn'tre-fire, and stale data from the previous table instance persists
Fix
Added a
resetNoncestate counter toPluginSlotInternalthat increments onevery
reset()call. This nonce is included in thefunctionMethodsuseMemodependency array, which causes the
searchfunction reference to change whenthe table instance changes.
useAsyncDatathen sees the new dependency andre-fires its fetch effect, pulling fresh data from the new table.