React中如何实现mouseout触发后取消RxJS的mouseover延迟执行流
问题根因
原来的实现中mouseover和mouseout是两个独立订阅的事件流,互相没有关联,因此mouseout事件无法打断mouseover流中已经启动的防抖计时器,即便提前移出元素,2秒后仍会触发mouseover状态更新,导致逻辑异常。
修正方案
通过RxJS组合操作符将两个事件流关联,实现可打断的延迟逻辑,完整代码如下:
import { fromEvent, of, mergeWith } from 'rxjs'; import { switchMap, debounceTime, takeUntil, tap } from 'rxjs/operators'; // ...组件内逻辑 useEffect(() => { const elMouseOver$ = fromEvent(elRef.current, "mouseover"); const elMouseOut$ = fromEvent(elRef.current, "mouseout"); const mainSub = elMouseOver$.pipe( // 每次移入触发时切换为新的内部延迟流,自动取消上一次未完成的流 switchMap(() => of(null).pipe( // 满足2秒延迟要求 debounceTime(2000), // 延迟期间触发移出则直接终止当前流,不执行后续逻辑 takeUntil(elMouseOut$), // 延迟满足后更新移入状态/发起AJAX请求 tap(() => setState({ hover: "mouseover", eventType: "mouseover" })) )), // 合并移出事件的状态更新逻辑 mergeWith( elMouseOut$.pipe( tap(() => setState({ hover: "mouseout", eventType: "mouseout" })) ) ) ).subscribe(); // 组件卸载时统一取消订阅,避免内存泄漏 return () => mainSub.unsubscribe(); }, []);
逻辑验证
- 鼠标移入后启动2秒延迟,到期后才执行状态更新,符合要求
- 延迟期间触发移出,
takeUntil会直接终止当前延迟流,不会触发移入状态更新,同时正常更新移出状态 - 延迟结束后触发移出,会正常更新移出状态
- 重复移入移出时,
switchMap会自动重置流程,重新开始计数
如果需要在延迟满足后发起AJAX请求,直接将of(null)替换为对应的RXJS AJAX请求流即可,请求同样会在提前移出时被自动取消。
内容的提问来源于stack exchange,提问作者user1724102
相关产品推荐
相关产品推荐

