Skip to content

fix: handle undefined sorts/customColumns from lazy+StrictMode defaultProps bug#2651

Closed
mofojed wants to merge 1 commit intodeephaven:mainfrom
mofojed:fix-iris-grid-default-props
Closed

fix: handle undefined sorts/customColumns from lazy+StrictMode defaultProps bug#2651
mofojed wants to merge 1 commit intodeephaven:mainfrom
mofojed:fix-iris-grid-default-props

Conversation

@mofojed
Copy link
Copy Markdown
Member

@mofojed mofojed commented Apr 6, 2026

When IrisGrid is loaded via LazyIrisGrid (the public export), it goes
through a forwardRef -> lazy() -> Suspense chain. In React 18 StrictMode,
there is a known bug (facebook/react#28505) where defaultProps are not
correctly merged into this.props during the second componentDidMount
call of the StrictMode double-mount cycle.

The root cause is in React's reconciler: during the simulated unmount,
componentWillUnmount sets instance.props to fiber.memoizedProps (the
unresolved props without defaultProps merged). When React re-mounts the
component, componentDidMount sees these unresolved props, so props like
sorts and customColumns are undefined instead of their defaultProps
values (EMPTY_ARRAY).

loadTableState() then sets these undefined values into state, and
IrisGridModelUpdater crashes with 'sorts is not iterable' when it
tries to spread them: [...sorts].

Add defensive ?? EMPTY_ARRAY fallbacks in:

  • IrisGrid.loadTableState(): when setting sorts/customColumns into state
  • IrisGridModelUpdater: when spreading sorts and assigning customColumns

Add tests that reproduce the exact bug by combining async lazy loading
with StrictMode, and unit tests for IrisGridModelUpdater with undefined
sorts/customColumns.

…tProps bug

When IrisGrid is loaded via LazyIrisGrid (the public export), it goes
through a forwardRef -> lazy() -> Suspense chain. In React 18 StrictMode,
there is a known bug (facebook/react#28505) where defaultProps are not
correctly merged into this.props during the second componentDidMount
call of the StrictMode double-mount cycle.

The root cause is in React's reconciler: during the simulated unmount,
componentWillUnmount sets instance.props to fiber.memoizedProps (the
unresolved props without defaultProps merged). When React re-mounts the
component, componentDidMount sees these unresolved props, so props like
sorts and customColumns are undefined instead of their defaultProps
values (EMPTY_ARRAY).

loadTableState() then sets these undefined values into state, and
IrisGridModelUpdater crashes with 'sorts is not iterable' when it
tries to spread them: `[...sorts]`.

Add defensive ?? EMPTY_ARRAY fallbacks in:
- IrisGrid.loadTableState(): when setting sorts/customColumns into state
- IrisGridModelUpdater: when spreading sorts and assigning customColumns

Add tests that reproduce the exact bug by combining async lazy loading
with StrictMode, and unit tests for IrisGridModelUpdater with undefined
sorts/customColumns.
@mofojed mofojed self-assigned this Apr 6, 2026
@mofojed
Copy link
Copy Markdown
Member Author

mofojed commented Apr 6, 2026

The bug is a React issue: facebook/react#28505
It only manifests in development mode when using StrictMode. I think I'd rather have it fail immediately than fail in other subtle ways. It does not affect production.
The correct fix is to convert to functional components and/or update to React v19. I'm going to close this ticket so it still fails hard and can be found when searching for issues, pointing to the React issue.

@mofojed mofojed closed this Apr 6, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant