TypeScript类中使用Material-UI RootRef绑定Popover时RefObject始终为null
问题根因与修复方案
this.PopoverRef.current始终为null,核心是三个使用上的问题叠加导致的:
- Popover是典型的条件渲染Portal组件,只有当传入的
open属性为true时,才会把内部浮层内容挂载到真实DOM上。你当前代码里没有给Popover配置open状态,组件从始至终没有完成实际DOM渲染,ref自然永远指向空值。 - API使用场景不匹配:从Material UI v4版本开始,包括Popover在内的绝大多数组件已经原生支持ref透传,不需要在外层额外包裹RootRef。RootRef是v3及更早版本为不支持ref转发的组件提供的过渡兼容API,当前把RootRef套在Popover外层时,RootRef无法捕获到Popover通过Portal异步渲染的浮层根节点,根本无法给ref赋值。
- 读取ref的时机错误:Popover的浮层是独立通过Portal异步挂载的,和父组件的生命周期并不完全同步。在父组件自身的
componentDidMount执行时,Popover大概率还没完成DOM挂载流程,此时读取ref永远拿不到有效值。
修正后的可运行代码
import React, { Component } from "react"; import { Popover } from "@material-ui/core"; class Home extends Component { // 修正ref类型,匹配Popover透传的DOM元素类型 private PopoverRef = React.createRef<HTMLDivElement>(); private anchorRef = React.createRef<HTMLButtonElement>(); // 在Popover完全挂载完成的回调里读取ref,此时值为真实DOM节点 handlePopoverMounted = () => { console.log(this.PopoverRef.current); // 可正常拿到DOM引用 } render() { return ( <> <button ref={this.anchorRef}>触发Popover</button> <Popover open={true} // 必须设置open属性,触发Popover实际渲染 ref={this.PopoverRef} // 直接给Popover传ref,无需额外包裹RootRef onEntered={this.handlePopoverMounted} // 绑定浮层挂载完成的回调 anchorEl={this.anchorRef.current} > 浮层内容 </Popover> </> ); } }
注意事项
- Popover透传的ref指向的是浮层本身的根DOM节点,如果你需要获取触发浮层的锚点元素,需要单独给锚点元素绑定ref,Popover组件不会自动捕获锚点的引用。
- 如果项目仍在使用v3及更早版本的Material UI,必须搭配RootRef使用ref的场景,也要保证Popover处于open渲染状态,同时在浮层的挂载完成回调里读取ref值,不要在父组件的挂载生命周期中提前读取。
内容的提问来源于stack exchange,提问作者ru4ert
相关产品推荐
相关产品推荐

