如何在React中获取DOM元素引用以使用rxjs的fromEvent方法订阅事件
问题原因
- 函数组件误用
React.createRef:React.createRef是为类组件设计的API,在函数组件中使用时每次重渲染都会生成全新的ref对象,无法持久化保存DOM引用,因此会出现current: null的问题,函数组件请使用useRef创建ref。 - 操作ref的时机早于组件挂载:ref的
current属性只有在对应DOM元素实际渲染挂载到页面后才会指向该元素,在组件挂载前(比如组件渲染逻辑同步执行时)访问ref,拿到的必然是null。
正确实现方案
函数组件实现(推荐)
使用useRef创建持久化ref,在useEffect回调中执行fromEvent订阅逻辑,useEffect空依赖的回调会在组件挂载完成后执行,此时ref已经绑定到真实DOM,同时要在返回的清理函数中取消订阅避免内存泄漏。
import { useRef, useEffect } from 'react'; import { fromEvent } from 'rxjs'; function App() { const buttonWait = useRef(null); useEffect(() => { // 组件挂载完成后,ref.current已经指向真实DOM元素 const click$ = fromEvent(buttonWait.current, 'click'); const subscription = click$.subscribe(() => { // 你的事件处理逻辑 console.log('Wait按钮被点击'); }); // 组件卸载时取消订阅,防止内存泄漏 return () => subscription.unsubscribe(); }, []); return <button ref={buttonWait}>Wait</button> }
类组件实现
类组件可以正常使用React.createRef,订阅逻辑要放在componentDidMount生命周期中执行,该生命周期触发时DOM已经完成挂载。
import React from 'react'; import { fromEvent } from 'rxjs'; class App extends React.Component { constructor(props) { super(props); this.buttonWait = React.createRef(); this.subscription = null; } componentDidMount() { const click$ = fromEvent(this.buttonWait.current, 'click'); this.subscription = click$.subscribe(() => { console.log('Wait按钮被点击'); }); } componentWillUnmount() { // 组件卸载时取消订阅 this.subscription?.unsubscribe(); } render() { return <button ref={this.buttonWait}>Wait</button> } }
条件渲染场景的特殊处理
如果按钮是通过状态控制是否渲染的,需要将控制按钮显示的状态变量加入useEffect的依赖数组,确保按钮渲染后再执行订阅逻辑:
import { useState, useRef, useEffect } from 'react'; import { fromEvent } from 'rxjs'; function App() { const [showWaitBtn, setShowWaitBtn] = useState(false); const buttonWait = useRef(null); useEffect(() => { // 元素未渲染时直接跳过订阅逻辑 if (!buttonWait.current) return; const click$ = fromEvent(buttonWait.current, 'click'); const subscription = click$.subscribe(() => { console.log('Wait按钮被点击'); }); return () => subscription.unsubscribe(); }, [showWaitBtn]); // 依赖加入控制按钮显示的状态 return ( <> <button onClick={() => setShowWaitBtn(!showWaitBtn)}> 切换Wait按钮显示 </button> {showWaitBtn && <button ref={buttonWait}>Wait</button>} </> ) }
内容的提问来源于stack exchange,提问作者Twilight
相关产品推荐
相关产品推荐

