javascript - setInterval 和 clearInterval 不能一起工作
问题描述
所以我有一个 setInterval 和 clearInterval 函数来分别启动和停止一个计数器。这里的问题是每次我单击按钮时,状态都会设置为 true,并且会触发计时器功能来启动计时器。现在再次单击计时器,计时器不会停止,因为 refreshIntervalId 变量现在具有未定义的值。请帮我解决这个问题!
这是我的代码:
if (timer == true) {
console.log("timer is playing");
refreshIntervalID = setInterval(timerFunction, 1000);
console.log(refreshIntervalID);
}
if (timer == false) {
console.log(refreshIntervalID);
clearInterval(refreshIntervalID);
}
这是完整的代码:
import React from "react";
import "./App.css";
import { useSelector, useDispatch } from "react-redux";
import { playToggle, reset } from "./actions/indexAction";
function Timer() {
const timer = useSelector((state) => state.timer);
const sessionLength = useSelector((state) => state.sessionLength);
let minutes = sessionLength;
let seconds = 60;
var refreshIntervalID;
const dispatch = useDispatch();
let resetClick = () => {
return dispatch(reset());
};
let timerFunction = () => {
if (timer == true) {
seconds--;
console.log(seconds);
}
};
if (timer == "reset") {
minutes = sessionLength;
seconds = 60;
console.log("Is Reset");
}
if (timer == true) {
console.log("timer is playing");
refreshIntervalID = setInterval(timerFunction, 1000);
console.log(refreshIntervalID);
}
if (timer == false) {
console.log(refreshIntervalID);
clearInterval(refreshIntervalID);
}
return (
<div>
<h1>Minutes: {minutes}</h1>
<h1>Minutes: {seconds}</h1>
<div>
<button onClick={() => dispatch(playToggle())}>PLAY/PAUSE</button>
</div>
<div>
<button onClick={resetClick}>RESET</button>
</div>
</div>
);
}
export default Timer;
解决方案
这并不完全相关,因为与之相关的评论结果并不完全准确:
你绝对不想在 redux reducer 中产生副作用。让副作用发生在组件中。原因是 reducer 应该是纯的,以使整个通量体系结构正常工作。在 reducer 中唯一应该有副作用的情况是,如果您使用的是像redux-loop这样的中间件。否则你会很快得到一些非常难以维护的代码。
如果这是在功能组件中,我是这样做的:
function(){
useEffect(()=>{
if (timer) {
console.log("timer is playing");
const refreshIntervalID = setInterval(timerFunction, 1000);
console.log(refreshIntervalID);
return ()=>{
clearInterval(refreshIntervalID)
}
}
},[timer])
}
您必须清除 useEffect 挂钩内的间隔
编辑:添加有希望的工作代码
import React, { useEffect, useState } from 'react';
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
import { playToggle } from './actions/indexAction';
function Timer() {
const timer = useSelector((state) => state.timer);
const sessionLength = useSelector((state) => state.sessionLength * 60); // session in seconds
const [seconds, setSeconds] = useState(sessionLength);
const [resetTimer, setResetTimer] = useState(0);
const dispatch = useDispatch();
let resetClick = () => {
// Get a new value every time
setSeconds(sessionLength);
setResetTimer((value) => value + 1);
};
useEffect(()=>{
// Set the timer to use the latest value when the session length changes.
setSeconds(sessionLength)
},[sessionLength])
useEffect(() => {
// Perform a side effect
if (timer) {
// Only run the timer when timer is truthy
let timerFunction = () => {
setSeconds((seconds) => seconds - 1);
};
console.log('timer is playing');
const refreshIntervalID = setInterval(timerFunction, 1000);
return () => {
// Clean up timer before effect runs again (or on unmount)
clearInterval(refreshIntervalID);
};
}
// Restart timer whenever timer, sessionLength, or resetTimer changes
}, [timer, resetTimer]);
useEffect(() => {
// If the timer has elapsed, stop the timer and reset.
if (seconds <= 0) {
dispatch(playToggle());
setSeconds(sessionLength);
}
}, [seconds, dispatch, sessionLength]);
return (
<div>
<h1>Minutes: {Math.floor(seconds / 60)}</h1>
<h1>Minutes: {seconds % 60}</h1>
<div>
<button onClick={() => dispatch(playToggle())}>PLAY/PAUSE</button>
</div>
<div>
<button onClick={resetClick}>RESET</button>
</div>
</div>
);
}
export default Timer;
推荐阅读
- angular - 如何在角度 4 中使用两个相同的路径 ='' 路由应用程序
- react-native - 在本机反应中将样式设置为导航选项内的自定义组件
- youtube-api - 每个人都需要自己的 YouTube API v3 密钥吗?
- python - 解读 sklearns 的 GridSearchCV 最佳成绩
- c# - C# 构造函数重载无用的括号
- ios - 在 ios 中将应用程序置于前台
- wordpress - 基于小计金额的 Woocommerce 税
- c - 精确宽度整数的实用可移植性
- java - 循环运行的多个 Kafka 消费者线程实例返回空
- sql - 如何使用 MERGE 或 Upsert Sql 语句