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

为什么React中Stopwatch类实例调用start()后isRunning属性仍为false?

问题原因

  1. React函数组件重渲染导致实例重复创建
    你直接在函数组件的顶层代码执行const stopwatch = new Stopwatch(),而函数组件每次状态变化触发重渲染时,都会从头到尾执行所有顶层代码,也就是说每重渲染一次就会生成一个全新的Stopwatch实例。你之前调用start()修改的是上一个实例的isRunning状态,后续调用stop()时用的是新生成的实例,新实例的isRunning默认值就是false,自然会触发"Stopwatch is already stopped"的报错,你观察到构造函数多次执行就是这个原因。
  2. 单实例场景下如果仍出现该问题,可检查是否在调用stop()之前,有其他逻辑提前调用了reset()方法,reset会主动把isRunning重置为false。

解决方法

第一步:固定Stopwatch实例

使用React的useRef存储Stopwatch实例,保证组件整个生命周期内只会生成一个实例:

import React, { useRef, useEffect } from 'react';
import { Button, Row, Col } from 'antd';
import { I18n } from 'aws-amplify';
import Stopwatch from '../../../../../utils/Stopwatch';

export default function TenMeter(props) {
    // 用useRef存实例,仅初始化时生成一次
    const stopwatchRef = useRef(new Stopwatch());

    const startTrial = async (index) => {
        stopwatchRef.current.start();
    }

    const completeTrial = async (index) => {
        stopwatchRef.current.stop();
        resetParameters();
    }

    const resetTrial = async (index) => {
        resetParameters();
    }

    const resetTest = (index) => {
        resetParameters();
    }

    const resetParameters = () => {
        stopwatchRef.current.reset();
    }

    // 组件卸载时清除定时器,避免内存泄漏
    useEffect(() => {
        return () => {
            stopwatchRef.current.reset();
        }
    }, [])

    function getTrialsButtonGroup(index) {
        return (
            <Row key={index} gutter={[16, 16]}>
                <Col xs={{ span: 24, offset: 0 }} lg={{ span: 24, offset: 0 }}>
                    <span>{I18n.get('Trial')} {index + 1}</span>
                    <Button style={{ marginLeft: "10px" }} onClick={() => startTrial(index)}>{I18n.get('Start')}</Button>
                    <Button style={{ marginLeft: "10px" }} onClick={() => resetTrial(index)}>{I18n.get('Reset')}</Button>
                    <Button style={{ marginLeft: "10px" }} onClick={() => completeTrial(index)}>{I18n.get('Stop')}</Button>
                </Col>
            </Row>
        )
    };

    return (
        <div>
                    {getTrialsButtonGroup(0)}
        </div>
    );
}

第二步:检查逻辑调用顺序

确认没有在start()之后、stop()之前主动调用reset()的逻辑,避免isRunning被提前重置。

内容的提问来源于stack exchange,提问作者kataba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 10:15:04