react-spectrum
react-spectrum copied to clipboard
useTabListState error if direct child is a React Fragment
๐ Bug Report
useTabListState fails with error Cannot convert a Symbol value to a string if tab items are wrapped in a react fragment
๐ค Expected Behavior
Should take fragment children as the tab items
๐ฏ Current Behavior
Tries to parse react fragment as a tab item. Here is the stack trace
module.js:232 Uncaught TypeError: Cannot convert a Symbol value to a string
at $f8429209754fda4b9142d514065f4$export$CollectionBuilder.getFullNode (module.js:232)
at getFullNode.next (<anonymous>)
at $f8429209754fda4b9142d514065f4$export$CollectionBuilder.iterateCollection (module.js:168)
at iterateCollection.next (<anonymous>)
at Object.[Symbol.iterator] (module.js:342)
at Generator.next (<anonymous>)
at new ListCollection (module.js:40)
at factory (module.js:116)
at module.js:378
at mountMemo (react-dom.development.js:15846)
getFullNode @ module.js:232
iterateCollection @ module.js:168
[Symbol.iterator] @ module.js:342
ListCollection @ module.js:40
factory @ module.js:116
(anonymous) @ module.js:378
mountMemo @ react-dom.development.js:15846
useMemo @ react-dom.development.js:16219
useMemo @ react.development.js:1532
useCollection @ module.js:376
useListState @ module.js:121
useSingleSelectListState @ module.js:148
useTabListState @ module.js:10
(anonymous) @ index.js:16
renderWithHooks @ react-dom.development.js:14985
updateForwardRef @ react-dom.development.js:17044
beginWork @ react-dom.development.js:19098
callCallback @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
beginWork$1 @ react-dom.development.js:23964
performUnitOfWork @ react-dom.development.js:22779
workLoopSync @ react-dom.development.js:22707
renderRootSync @ react-dom.development.js:22670
performSyncWorkOnRoot @ react-dom.development.js:22293
scheduleUpdateOnFiber @ react-dom.development.js:21881
updateContainer @ react-dom.development.js:25482
(anonymous) @ react-dom.development.js:26021
unbatchedUpdates @ react-dom.development.js:22431
legacyRenderSubtreeIntoContainer @ react-dom.development.js:26020
render @ react-dom.development.js:26103
(anonymous) @ render.js:40
render @ render.js:39
_callee$ @ render.js:131
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ render.js:9
_next @ render.js:11
(anonymous) @ render.js:11
(anonymous) @ render.js:11
_renderMain @ render.js:140
renderMain @ render.js:103
_callee3$ @ StoryRenderer.js:379
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
Promise.then (async)
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
renderStory @ StoryRenderer.js:411
_callee2$ @ StoryRenderer.js:257
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
renderStoryIfChanged @ StoryRenderer.js:281
_callee$ @ StoryRenderer.js:151
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
renderCurrentStory @ StoryRenderer.js:165
(anonymous) @ StoryRenderer.js:78
(anonymous) @ index.js:168
handleEvent @ index.js:167
handler @ index.js:93
emit @ index.js:100
setSelection @ story_store.js:859
finishConfiguring @ story_store.js:393
ConfigApi.configure @ config_api.js:26
(anonymous) @ loadCsf.js:254
configure @ index.js:19
(anonymous) @ generated-stories-entry.js:6
./.storybook/generated-stories-entry.js @ generated-stories-entry.js:6
__webpack_require__ @ bootstrap:853
fn @ bootstrap:150
0 @ global.css?3d5c:82
__webpack_require__ @ bootstrap:853
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.iframe.bundle.js:1
Show 61 more frames
react-dom.development.js:20085 The above error occurred in the <FynTabs> component:
at http://localhost:6006/main.iframe.bundle.js:17707:24
at div
at unboundStoryFn (http://localhost:6006/vendors~main.iframe.bundle.js:44589:30)
at ErrorBoundary (http://localhost:6006/vendors~main.iframe.bundle.js:56678:5)
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
logCapturedError @ react-dom.development.js:20085
update.payload @ react-dom.development.js:20133
getStateFromUpdate @ react-dom.development.js:12102
processUpdateQueue @ react-dom.development.js:12250
resumeMountClassInstance @ react-dom.development.js:12921
updateClassComponent @ react-dom.development.js:17430
beginWork @ react-dom.development.js:19073
beginWork$1 @ react-dom.development.js:23940
performUnitOfWork @ react-dom.development.js:22779
workLoopSync @ react-dom.development.js:22707
renderRootSync @ react-dom.development.js:22670
performSyncWorkOnRoot @ react-dom.development.js:22293
scheduleUpdateOnFiber @ react-dom.development.js:21881
updateContainer @ react-dom.development.js:25482
(anonymous) @ react-dom.development.js:26021
unbatchedUpdates @ react-dom.development.js:22431
legacyRenderSubtreeIntoContainer @ react-dom.development.js:26020
render @ react-dom.development.js:26103
(anonymous) @ render.js:40
render @ render.js:39
_callee$ @ render.js:131
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ render.js:9
_next @ render.js:11
(anonymous) @ render.js:11
(anonymous) @ render.js:11
_renderMain @ render.js:140
renderMain @ render.js:103
_callee3$ @ StoryRenderer.js:379
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
Promise.then (async)
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
renderStory @ StoryRenderer.js:411
_callee2$ @ StoryRenderer.js:257
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
renderStoryIfChanged @ StoryRenderer.js:281
_callee$ @ StoryRenderer.js:151
tryCatch @ runtime.js:63
invoke @ runtime.js:293
(anonymous) @ runtime.js:118
asyncGeneratorStep @ StoryRenderer.js:13
_next @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
(anonymous) @ StoryRenderer.js:15
renderCurrentStory @ StoryRenderer.js:165
(anonymous) @ StoryRenderer.js:78
(anonymous) @ index.js:168
handleEvent @ index.js:167
handler @ index.js:93
emit @ index.js:100
setSelection @ story_store.js:859
finishConfiguring @ story_store.js:393
ConfigApi.configure @ config_api.js:26
(anonymous) @ loadCsf.js:254
configure @ index.js:19
(anonymous) @ generated-stories-entry.js:6
./.storybook/generated-stories-entry.js @ generated-stories-entry.js:6
__webpack_require__ @ bootstrap:853
fn @ bootstrap:150
0 @ global.css?3d5c:82
__webpack_require__ @ bootstrap:853
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.iframe.bundle.js:1
Show 48 more frames
index.js:54 TypeError: Cannot convert a Symbol value to a string
at $f8429209754fda4b9142d514065f4$export$CollectionBuilder.getFullNode (module.js:232)
at getFullNode.next (<anonymous>)
at $f8429209754fda4b9142d514065f4$export$CollectionBuilder.iterateCollection (module.js:168)
at iterateCollection.next (<anonymous>)
at Object.[Symbol.iterator] (module.js:342)
at Generator.next (<anonymous>)
at new ListCollection (module.js:40)
at factory (module.js:116)
at module.js:378
at mountMemo (react-dom.development.js:15846)
๐ Possible Solution
๐ฆ Context
Rendering different children based on a condition eg
<>
{
casSeeThis && (<>...</>)
}
...
</>
or if you are providing the children prop as part of an object { children: <>...</>}
This makes it a requirement to manually drill into the children prop and check for child type before passing them onto state. I understand the lib should not do everything for you. So if this issue will not be fixed. Documentation on how to get around it or to get around wrapping any of the expected direct children, would be a great help as the error given is not helpful.
๐ป Code Sample
๐ Your Environment
| Software | Version(s) |
|---|---|
| @react-stately/tabs | ^3.0.0 |
| react | ^17.0.2 |
| react-dom | ^17.0.2 |
| @storybook/react | ^6.2.8 |
| Browser | chrome |
| Operating System | windows 10 |
๐งข Your Company/Team
๐ท Tracking Issue (optional)
The first sentence of this section should help https://react-spectrum.adobe.com/react-stately/collections.html#dynamic-collections Essentially you have a collection that needs to change, so you'll need to create a new 'items' object to pass in, with or without the tab you're trying to conditionally render. You'll notice, for example, that if you try to conditionally apply anything to static collections, it won't update the rendered output. We don't have access to React internals and therefore can't know if a child of the collection was updated. Any state that may cause a different render needs to be passed into items
Hey! good news, talked with the team, we think this could be supported in https://github.com/adobe/react-spectrum/blob/main/packages/@react-stately/collections/src/CollectionBuilder.ts General gist would be that we know when we come across a React Fragment and so we can look at the children. We can't do this in other cases as we don't know the element types, but for React Fragment this should be ok.
Hi, any updates on that? I have the same problem with list component
I believe this has been addressed in our new collections implementation https://codesandbox.io/p/sandbox/pedantic-lovelace-pqjllx?file=%2Fsrc%2FApp.js%3A25%2C10 We use them in our RAC components. We haven't documented it for just hooks yet, and we haven't implemented it in our react spectrum components yet.
Feel free to have a look at the source for the RAC components though.
@snowystinger - would #6430 fix it in CollectionBuilder?
@solimant I believe so. I don't have a codesandbox for the original issue, I'm going to close this now. If there's still an issue, please provide a codesandbox.