React Modal组件无法在Storybook中显示的技术问询
Let's break down why your Modal isn't rendering correctly in Storybook and fix each issue step by step:
1. The Root Problem: Early DOM Element Query
In your Modal component, you're querying for the #modal container at the module top level:
const modal = document.getElementById('modal')
When your component module loads (before Storybook renders the decorator that creates the #modal div), this returns null. You create a new div but never actually append it to the #modal container—so the portal has nowhere to mount.
Fix the Portal Mount Logic
Rewrite your Modal component to handle the portal container dynamically with React hooks, ensuring we only interact with the DOM after it exists:
import { useEffect, useRef } from 'react'; import ReactDOM from 'react-dom'; const Modal = ({ open, onClose, children, position }) => { // Create a ref for our portal container div const portalContainerRef = useRef(document.createElement('div')); useEffect(() => { // Get the #modal container AFTER the component mounts const modalRoot = document.getElementById('modal'); if (modalRoot) { // Append our portal container to the root modalRoot.appendChild(portalContainerRef.current); } // Clean up: remove the container when the component unmounts return () => { if (modalRoot) { modalRoot.removeChild(portalContainerRef.current); } }; }, []); // Don't render anything if the modal isn't open if (!open) return null; return ReactDOM.createPortal( <> <Backdrop onClick={onClose}> <ModalBox> <Wrapper position={position}> {children} {/* Add onClick to CloseIcon to trigger onClose */} <CloseIcon icon={faTimesCircle} onClick={onClose} /> </Wrapper> </ModalBox> </Backdrop> </>, portalContainerRef.current // Use our ref'd container for the portal ); };
2. Storybook State & Interaction Issues
Your Storybook story has two missing pieces that break the user experience:
- The "Show Modal" button doesn't have a click handler to open the modal
- You're using the
booleanknob directly without tying it to component state (so toggling the knob won't update the modal's open state properly)
Fix the Storybook Story
Update your story to manage state with useState and wire up the button interaction:
import { storiesOf } from '@storybook/react'; import { withKnobs, boolean } from '@storybook/addon-knobs'; import { useState } from 'react'; import Modal from './Modal'; storiesOf('Modals', module) .addDecorator(storyFn => ( // Simplify the decorator—we just need the #modal container <div id="modal"> {storyFn()} </div> )) .addDecorator(withKnobs) .add('Modals - Basic', () => { // Sync knob value with local state for proper reactivity const initialOpen = boolean('open', false); const [open, setOpen] = useState(initialOpen); return ( <> <button type="button" onClick={() => setOpen(true)}>Show Modal</button> <Modal open={open} onClose={() => setOpen(false)} // Pass onClose to update state > <Modal.Header>Modal Header goes here</Modal.Header> <Modal.Content>Modal Content goes here</Modal.Content> <Modal.Footer>Modal Footer goes here</Modal.Footer> </Modal> </> ); });
3. Bonus: Fix Close Icon Interaction
Notice in the updated Modal component we added onClick={onClose} to the CloseIcon—your original code didn't bind this event, so clicking the close icon wouldn't have closed the modal anyway.
After applying these fixes, your modal should render correctly in Storybook: clicking the button will open it, clicking the backdrop or close icon will close it, and the knob will let you toggle the initial open state.
内容的提问来源于stack exchange,提问作者milan

