RXJS如何实现点击按钮取消订阅且可通过其他按钮重新订阅
RxJS 按钮控制订阅启停实现方案
原有写法存在两个核心问题:
- 嵌套订阅会导致内部
count3的订阅不受外层click1订阅的管理,即便取消click1的订阅,count3仍然会持续触发回调sub.unsubscribe()没有绑定到button2的点击事件回调中,只会在代码初始化时执行一次
核心实现逻辑
- 声明变量存储计数流的活跃订阅实例,避免重复订阅
- 点击第一个按钮时,先销毁已存在的订阅,再生成新的订阅存储到变量中
- 点击第二个按钮时,调用存储的订阅实例的
unsubscribe方法销毁订阅,并清空存储变量
基础实现(命令式,逻辑直观)
import { mapTo, scan } from 'rxjs/operators' import { fromEvent, Subscription } from 'rxjs' const button1 = document.getElementById("but1") const button2 = document.getElementById("but2") const button3 = document.getElementById("but3") const d = document.getElementById("d") const p3 = document.createElement("p") d?.appendChild(p3) // 存储count3的活跃订阅实例 let count3Sub: Subscription | null = null // 按钮3的计数逻辑 const click3 = fromEvent(button3, 'click') const three = click3.pipe(mapTo(1)) const count3 = three.pipe(scan((acc, val) => acc + val, 0)) // 按钮1点击:开启订阅 fromEvent(button1, 'click').subscribe(() => { // 先销毁已存在的订阅,避免重复触发回调 if (count3Sub) count3Sub.unsubscribe() count3Sub = count3.subscribe(x => p3.innerHTML = `Click count: ${x}`) }) // 按钮2点击:取消订阅 fromEvent(button2, 'click').subscribe(() => { if (count3Sub) { count3Sub.unsubscribe() count3Sub = null } })
进阶实现(RxJS 声明式风格)
无需手动维护订阅变量,通过RxJS内置操作符自动管理流生命周期,更符合响应式编程规范:
import { mapTo, scan, takeUntil, switchMap } from 'rxjs/operators' import { fromEvent, Subject } from 'rxjs' const button1 = document.getElementById("but1") const button2 = document.getElementById("but2") const button3 = document.getElementById("but3") const d = document.getElementById("d") const p3 = document.createElement("p") d?.appendChild(p3) // 停止信号发射器 const stop$ = new Subject<void>() // 按钮2点击触发停止信号 fromEvent(button2, 'click').subscribe(() => stop$.next()) // 按钮3计数流 const count3$ = fromEvent(button3, 'click').pipe( mapTo(1), scan((acc, val) => acc + val, 0) ) // 按钮1点击时切换到计数流,直到收到停止信号自动终止 fromEvent(button1, 'click').pipe( switchMap(() => count3$.pipe(takeUntil(stop$))) ).subscribe(x => p3.innerHTML = `Click count: ${x}`)
内容的提问来源于stack exchange,提问作者Matthew Kna
相关产品推荐
相关产品推荐

