React父组件状态传入子组件后无法正常修改问题求助
React模态框无法关闭问题排查与解决
点击父组件的Project容器可以正常打开模态框,但点击子组件ProjectModal中的X按钮时,无法将modal状态设为false,模态框始终无法关闭,尝试props.setModal(false)、props.setModal(!props.modal)均无效。
问题代码
interface ModalProps extends Project { setModal: (modal: boolean) => void, modal: boolean } export default function Projects(props: Project) { const [modal, setModal] = useState<boolean>(false) let showOrHideModal = modal ? 'inline' : 'hidden' return ( <div onClick={() => setModal(true)}> <div className={showOrHideModal}> <ProjectModal {...props} setModal={setModal} modal={modal} /> </div> </div> ) } function ProjectModal(props: ModalProps) { return ( <X onClick={() => { console.log('X clicked'); props.setModal(false); console.log(props.modal) }} /> ) }
问题根源
核心原因是事件冒泡:X按钮的点击事件会向上冒泡到父级的<div onClick={() => setModal(true)}>容器,导致刚通过props.setModal(false)把状态改成false,立刻又被父元素的事件回调改成true,视觉上就表现为模态框关不掉。
另外,console.log(props.modal)打印的是旧值,因为React状态更新是异步的,不会立刻同步到props里,这属于正常现象,不是导致关不掉的原因。
解决方法
方法1:阻止X按钮的事件冒泡
在X按钮的点击事件中调用e.stopPropagation(),阻止事件向上传递:
function ProjectModal(props: ModalProps) { return ( <X onClick={(e) => { e.stopPropagation(); // 阻止事件冒泡 console.log('X clicked'); props.setModal(false); }} /> ) }
方法2:调整DOM结构,分离触发容器与模态框容器
把模态框的容器移到触发点击的div外面,避免事件冒泡影响:
export default function Projects(props: Project) { const [modal, setModal] = useState<boolean>(false) let showOrHideModal = modal ? 'inline' : 'hidden' return ( <> <div onClick={() => setModal(true)}>点击打开模态框</div> <div className={showOrHideModal}> <ProjectModal {...props} setModal={setModal} modal={modal} /> </div> </> ) }
方法3:缩小触发区域
不要把整个父div作为打开模态框的触发区域,给具体的触发元素(比如按钮、标题)单独绑定点击事件,避免模态框的点击事件冒泡到触发元素上。
内容的提问来源于stack exchange,提问作者Cadhig
相关产品推荐
相关产品推荐

