React中父组件传Props控制子组件Modal状态失效,如何解决?
模态窗口无法通过父组件props触发打开的问题分析与解决
问题场景
父组件AlbumList代码:
interface AlbumListProps { albums: AlbumType[]; } const AlbumList = (props: AlbumListProps) => { const [open, setOpen] = useState(false); let albumToEdit; const handleEdit = () => { setOpen(true); }; return ( <> <button onClick={handleEdit} > Edit </button> <Modal openModal={open} /> </> ); };
子组件Modal(模态窗口)代码:
const Modal = (props: any) => { const { openModal } = props; const [open, setOpen] = useState(openModal); const cancelButtonRef = useRef(null); return ( <Transition.Root show={open} as={Fragment}> <Dialog as='div' initialFocus={cancelButtonRef} onClose={setOpen} > <Transition.Child as={Fragment} > <Dialog.Panel> <Dialog.Title> Some text </Dialog.Title> <button type='button' onClick={() => setOpen(false)} ref={cancelButtonRef} > Cancel </button> </Dialog.Panel> </Transition.Child> </Dialog> </Transition.Root> ); };
点击父组件的Edit按钮后,父组件open状态变为true并传递给Modal的openModal props,但模态窗口无法打开;若直接将Modal的初始状态设为const [open, setOpen] = useState(true),模态窗口能正常显示。
问题原因
useState的初始值仅在组件首次渲染时生效,后续父组件传递的openModal变化不会自动更新子组件内部的open状态。- 首次渲染时父组件
open为false,Modal的open状态被初始化为false;当点击Edit按钮后,父组件open变为true,但Modal内部的open状态不会同步这个变化,因此模态窗口仍保持关闭。
解决方法
方法一:直接复用父组件props,移除子组件独立状态
如果模态窗口的显示状态完全由父组件控制,无需子组件维护独立状态,直接使用props.openModal控制显示,同时将关闭逻辑回调给父组件:
// 修改后的Modal组件 const Modal = (props: { openModal: boolean; onClose: () => void }) => { const { openModal, onClose } = props; const cancelButtonRef = useRef(null); return ( <Transition.Root show={openModal} as={Fragment}> <Dialog as='div' initialFocus={cancelButtonRef} onClose={onClose} > <Transition.Child as={Fragment} > <Dialog.Panel> <Dialog.Title> Some text </Dialog.Title> <button type='button' onClick={onClose} ref={cancelButtonRef} > Cancel </button> </Dialog.Panel> </Transition.Child> </Dialog> </Transition.Root> ); };
// 修改后的AlbumList组件 const AlbumList = (props: AlbumListProps) => { const [open, setOpen] = useState(false); let albumToEdit; const handleEdit = () => { setOpen(true); }; const handleCloseModal = () => { setOpen(false); }; return ( <> <button onClick={handleEdit} > Edit </button> <Modal openModal={open} onClose={handleCloseModal} /> </> ); };
方法二:用useEffect同步父组件props到子组件状态
如果子组件需要维护独立状态(比如有额外的本地逻辑),可以通过useEffect监听openModal的变化,同步更新子组件的open状态:
// 修改后的Modal组件 const Modal = (props: { openModal: boolean }) => { const { openModal } = props; const [open, setOpen] = useState(openModal); const cancelButtonRef = useRef(null); useEffect(() => { setOpen(openModal); }, [openModal]); return ( <Transition.Root show={open} as={Fragment}> <Dialog as='div' initialFocus={cancelButtonRef} onClose={() => setOpen(false)} > <Transition.Child as={Fragment} > <Dialog.Panel> <Dialog.Title> Some text </Dialog.Title> <button type='button' onClick={() => setOpen(false)} ref={cancelButtonRef} > Cancel </button> </Dialog.Panel> </Transition.Child> </Dialog> </Transition.Root> ); };
内容的提问来源于stack exchange,提问作者dariusz
相关产品推荐
相关产品推荐

