Skip to content

fix: table data not refreshing after mo.output.replace() when first-page data is unchanged#8066

Merged
mscolnick merged 2 commits intomainfrom
ms/8023
Feb 3, 2026
Merged

fix: table data not refreshing after mo.output.replace() when first-page data is unchanged#8066
mscolnick merged 2 commits intomainfrom
ms/8023

Conversation

@mscolnick
Copy link
Contributor

@mscolnick mscolnick commented Jan 30, 2026

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 mounteduseState 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.

@vercel
Copy link

vercel bot commented Jan 30, 2026

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

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jan 30, 2026 10:03pm

Request Review

…-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.
@mscolnick mscolnick changed the title ms/8023 fix: table data not refreshing after mo.output.replace() when first-page data is unchanged Jan 30, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 resetNonce counter to PluginSlotInternal that increments on reset() 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.

@mscolnick mscolnick merged commit caf9a99 into main Feb 3, 2026
51 of 52 checks passed
@mscolnick mscolnick deleted the ms/8023 branch February 3, 2026 14:58
@github-actions
Copy link

github-actions bot commented Feb 3, 2026

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.19.8-dev9

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mo.ui.table: Rows that change pages due to UI sorting don't refresh after data updates

3 participants