为了账号安全,请及时绑定邮箱和手机立即绑定

clearInterval 不会在 React.useEffect 挂钩中被调用

clearInterval 不会在 React.useEffect 挂钩中被调用

至尊宝的传说 2023-01-06 15:58:06

我的 React 游戏有一个<Clock/>组件来跟踪时间。


当游戏暂停时,计时器应该停止。


我正在使用 Redux 来管理播放/暂停状态以及经过的时间。


const initialState = { inProgress: false, timeElapsed: 0 }

inProgress状态由另一个组件上的按钮处理,该按钮分派一个操作来更新商店(仅针对值inProgress)。


该组件在其钩子中<Clock/>递增。然而并不清楚。timeElapseduseEffectsetInterval


import React from 'react';

import { connect } from 'react-redux';


const Clock = ({ dispatch, inProgress, ticksElapsed }) => {


    React.useEffect(() => {


        const progressTimer = setInterval(function(){

            inProgress ? dispatch({ type: "CLOCK_RUN" }) : clearInterval(progressTimer);

        }, 1000)


    }, [inProgress]);


    return (

        <></>

    )

};


let mapStateToProps = ( state ) => {

    let { inProgress, ticksElapsed } = state.gameState;

    return { inProgress, ticksElapsed };

}


export default connect(

    mapStateToProps,

    null,

)(Clock);

在里面setInterval,什么时候inProgress,false我希望clearInterval(progressTimer)时钟停止。


此外,还有另一个问题,即省略[inProgress]in useEffecthook 会导致计时器以荒谬的速度增加,从而导致应用程序崩溃。


谢谢你。


查看完整描述

1 回答

?
桃花长相依

TA贡献1598条经验 获得超8个赞

inProgress是传递给 setInterval 的函数的陈旧闭包。

可以通过清除cleanup函数中的interval来解决:

const Clock = ({ dispatch, inProgress, ticksElapsed }) => {

  React.useEffect(() => {

    const progressTimer = setInterval(function () {

      inProgress && dispatch({ type: 'CLOCK_RUN' });

    }, 500);

    return () =>

      //inprogress is stale so when it WAS true

      //  it must now be false for the cleanup to

      //  be called

      inProgress && clearInterval(progressTimer);

  }, [dispatch, inProgress]);


  return <h1>{ticksElapsed}</h1>;

};


const App = () => {

  const [inProgress, setInProgress] = React.useState(false);

  const [ticksElapsed, setTicksElapsed] = React.useState(0);

  const dispatch = React.useCallback(

    () => setTicksElapsed((t) => t + 1),

    []

  );

  return (

    <div>

      <button onClick={() => setInProgress((p) => !p)}>

        {inProgress ? 'stop' : 'start'}

      </button>

      <Clock

        inProgress={inProgress}

        dispatch={dispatch}

        ticksElapsed={ticksElapsed}

      />

    </div>

  );

};

ReactDOM.render(<App />, document.getElementById('root'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<div id="root"></div>


查看完整回答
反对 回复 2023-01-06
  • 1 回答
  • 0 关注
  • 7 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信