You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅使用RxJS操作符实现React自定义计时器清零并重启间隔

RxJS 自定义计时器重置功能修复方案

原有代码核心问题

  • 重置按钮点击回调未向 actionReset$ 发送信号:当前写为 () => actionReset$ 仅返回了Subject实例,未调用 .next() 触发事件,导致 repeatWhen 无法收到重置通知
  • interval 流声明在组件外部,多次挂载组件会复用同一个流,出现状态串扰
  • useEffect 依赖仅设置了 timerOn,存在闭包陷阱,订阅回调中读取的状态永远是初始挂载时的值
  • 未绑定重置时将 time 置为0的逻辑,就算重启了间隔流也不会清零计时值
  • 未定义 onStopClick 方法,Stop按钮无响应

修正后代码实现

import { useState, useEffect } from 'react';
import { interval, Subject, takeUntil, switchMap, tap } from 'rxjs';

function CustomTimer () {
  const [time, setTime] = useState(0);
  const [timerOn, setTimerOn] = useState(false);
  // 所有Subject放到组件内部,避免多实例串扰
  const actionReset$ = new Subject();
  const actionStop$ = new Subject();
  const unmount$ = new Subject();

  useEffect(() => {
    if (!timerOn) {
      // 计时器未开启时直接返回
      return () => unmount$.next();
    }

    // 构建计时流
    const subscription = actionReset$.pipe(
      // 每次重置信号触发时,先把时间清0,再启动新的interval流
      tap(() => setTime(0)),
      switchMap(() => interval(1000)),
      // 收到停止信号或者组件卸载时终止流
      takeUntil(actionStop$),
      takeUntil(unmount$)
    ).subscribe(count => {
      setTime(count + 1);
    });

    // 组件挂载/计时器开启时先触发一次重置,启动首次计时
    actionReset$.next();

    return () => {
      subscription.unsubscribe();
      unmount$.next();
    };
  }, [timerOn]);

  const onStopClick = () => {
    actionStop$.next();
    setTimerOn(false);
  };

  return (
    <div className="mainBlock">
      {!timerOn && (
        <button onClick={() => setTimerOn(true)}>Start</button>
      )}
      {timerOn && (
        <button onClick={onStopClick}>Stop</button>
      )}
      {time > 0 && (
        {/* 点击重置按钮发送信号 */}
        <button onClick={() => actionReset$.next()}>Reset</button>
      )}
      <div>当前计时:{time}秒</div>
    </div>
  );
}

export default CustomTimer;

关键改动说明

  • 用 switchMap 切换流:每次收到重置信号时,销毁旧的interval流,启动新的流,天然实现间隔重启
  • 重置信号触发时先用 tap 操作符执行置0逻辑,满足重置为0的需求
  • 新增 actionStop$ 处理停止逻辑,和重置逻辑解耦
  • 所有RxJS流放到组件内部,避免多实例冲突
  • 修复了重置按钮的点击事件,正确调用 .next() 发送信号

内容的提问来源于stack exchange,提问作者Александр Соколов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 19:09:04