React 16.3.2中componentDidMount无法获取ref问题求助
解决React 16.3.2中createRef在componentDidMount里获取DOM节点为null的问题
你遇到的应该是Cannot read property 'select' of null的报错——说白了就是在componentDidMount执行时,this.textarea.current还没成功拿到textarea的DOM节点。这在React 16.3.2这个刚推出createRef的版本里,路由切换场景下偶尔会出现,因为ref的赋值时机和组件挂载的生命周期存在微小延迟。
给你两个实用的解决方案:
方案一:改用回调Ref(稳定性更高)
回调Ref是React更早的Ref实现,在早期版本里比刚推出的createRef更靠谱,能确保DOM节点被精准捕获:
export default class ActivityPage extends React.Component { constructor(props) { super(props); // 初始化变量存储DOM节点 this.textarea = null; // 定义回调Ref函数 this.setTextareaRef = (element) => { this.textarea = element; }; } componentDidMount() { // 先判断节点是否存在,再执行select操作 if (this.textarea) { this.textarea.select(); } } render() { return ( <div> <textarea defaultValue="the quick brown fox." ref={this.setTextareaRef} /> </div> ); } }
方案二:延迟执行select(兼容createRef)
如果想继续用createRef,可以通过setTimeout或requestAnimationFrame延迟执行select方法,确保DOM完全渲染、Ref已经正确赋值:
用setTimeout的写法:
export default class ActivityPage extends React.Component { constructor(props) { super(props); this.textarea = React.createRef(); } componentDidMount() { // 延迟0毫秒执行,让浏览器先完成DOM渲染流程 setTimeout(() => { if (this.textarea.current) { this.textarea.current.select(); } }, 0); } render() { return ( <div> <textarea defaultValue="the quick brown fox." ref={this.textarea} /> </div> ); } }
用requestAnimationFrame的写法(更贴合浏览器渲染周期):
componentDidMount() { requestAnimationFrame(() => { // 可选:用可选链操作符简化判断(若项目支持babel转译,16.3.2也能用) this.textarea.current?.select(); }); }
问题原因说明
React 16.3.2是createRef的第一个正式版本,在路由切换这种异步挂载组件的场景下,Ref的赋值可能会稍微滞后于componentDidMount的执行时机,导致此时current为null。上面的两种方案都是通过确保DOM节点存在后再执行操作来规避这个问题。
内容的提问来源于stack exchange,提问作者E. Shcherbo
相关产品推荐
相关产品推荐

