adobe / react-spectrum

A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.
https://react-spectrum.adobe.com
Apache License 2.0
12.83k stars 1.11k forks source link

When copy pasting Select and ComboBox examples of React-Aria Components I get an error #4633

Closed patricklafrance closed 1 year ago

patricklafrance commented 1 year ago

πŸ› Bug Report

I copy/pasted the Select components "Reusable Wrappers" example of React-Aria component in my project and I get the following error at runtime:

Unhandled Runtime Error
TypeError: Cannot destructure property 'arrowProps' of '(0 , react__WEBPACK_IMPORTED_MODULE_0__.useContext)(...)' as it is null.

Copy pasted the "Reusable Wrapper" exemple and then using it like this (I renamed MyItem to MySelectItem):

<MySelect label="Ice cream flavor">
       <MySelectItem>Chocolate</MySelectItem>
       <MySelectItem>Mint</MySelectItem>
        <MySelectItem>Strawberry</MySelectItem>
        <MySelectItem>Vanilla</MySelectItem>
</MySelect>

πŸ€” Expected Behavior

No error at runtime.

😯 Current Behavior

Unhandled Runtime Error
TypeError: Cannot destructure property 'arrowProps' of '(0 , react__WEBPACK_IMPORTED_MODULE_0__.useContext)(...)' as it is null.

Call Stack
$44f671af83e7d9e0$var$OverlayArrow
node_modules\.pnpm\react-aria-components@1.0.0-alpha.4_react-dom@18.2.0_react@18.2.0\node_modules\react-aria-components\dist\import.mjs (1954:10)
renderWithHooks
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (10648:0)
updateForwardRef
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (14677:0)
beginWork$1
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (17369:0)
beginWork
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (25650:0)
performUnitOfWork
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24501:0)
workLoopSync
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24217:0)
renderRootSync
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24182:0)
recoverFromConcurrentError
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (23428:0)
performConcurrentWorkOnRoot
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (23334:0)
workLoop
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (261:0)
flushWork
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (230:0)
MessagePort.performWorkUntilDeadline
node_modules\.pnpm\next@13.4.4_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (537:0)

πŸ’ Possible Solution

πŸ”¦ Context

πŸ’» Code Sample

Here a Github repository with the code: https://github.com/patricklafrance/next13-react-aria/blob/main/app/react-aria/MySelect.tsx

Uncomment the following code in app/react-aria/page.tsx:

{/* <div>
    <h2>Select</h2>
    <MySelect label="Ice cream flavor">
        <MySelectItem>Chocolate</MySelectItem>
        <MySelectItem>Mint</MySelectItem>
        <MySelectItem>Strawberry</MySelectItem>
        <MySelectItem>Vanilla</MySelectItem>
    </MySelect>
</div> */}

🌍 Your Environment

Software Version(s)
react-spectrum 3.27.0
react-aria 3.25.0
react-aria-components 1.0.0-alpha.4
Next.js (with the App folder) 13.4.4
Browser Chrome 113
Operating System Windows

🧒 Your Company/Team

πŸ•· Tracking Issue (optional)

LFDanLu commented 1 year ago

This seems like it is because Select has preserveChildren set to true, causing the child Popover to render its children even when the state is closed. Usually this isn't a problem, but OverlayArrow expects to receive arrowProps from a context that only is available when the Popover is actually open. We should add a || {} or make sure that the OverlayArrowContext is available if preserveChildren is true

ealvarezk commented 1 year ago

is there a workaround for this issue?

LFDanLu commented 1 year ago

@ealvarezk you could try leveraging the Select's isOpen renderProps to conditionally render the OverlayArrow perhaps.

  <Select>
    {({isOpen}) => (
      <>
        <Label style={{display: 'block'}}>Test</Label>
        <Button>
          <SelectValue />
          <span aria-hidden="true" style={{paddingLeft: 5}}>{isOpen ? 'β–²' : 'β–Ό'}</span>
        </Button>
        <Popover>
          {isOpen && (
            <OverlayArrow>
              <svg width={12} height={12}><path d="M0 0,L6 6,L12 0" /></svg>
            </OverlayArrow>
          )}
          <ListBox className={styles.menu}>
            <MyItem>Foo</MyItem>
            <MyItem>Bar</MyItem>
            <MyItem>Baz</MyItem>
          </ListBox>
        </Popover>
      </>
    )}
  </Select>

Otherwise this would require changes in the OverlayArrow code like I mentioned above (aka adding a fallback like || {arrowProps: {style: {top: 0}})