这个反应组件中的这个调用堆栈有问题吗?
Is some wrong with this call stack in this react component?
我试图制作一个秒表计数器,但是当我调用“startTimer”函数时,setInterval 函数在 setStartTime 之前触发(在我第二次单击开始按钮后触发)。
import React from "react";
import { useState, useRef } from "react";
import RunButton from "./RunButton";
const RunTimer = () => {
const [timerOn, setTimerOn] = useState(false);
const [startTime, setStartTime] = useState(0);
const [timerTime, setTimerTime] = useState(0);
const timerInterval = useRef(null);
const startTimer = () => {
setTimerOn(true);
setStartTime(Date.now() - timerTime);
timerInterval.current = setInterval(() => {
setTimerTime(Date.now() - startTime);
}, 1000);
};
const stopTimer = () => {
setTimerOn(false);
clearInterval(timerInterval);
};
const resetTimer = () => {
setStartTime(0);
setTimerTime(0);
};
let seconds = Math.floor(timerTime / 1000) % 60;
let minutes = Math.floor(timerTime / 1000 / 60) % 60;
return (
<div className="text-6xl font-medium text-center">
{minutes < 10 ? `0${minutes}` : minutes}:
{seconds < 10 ? `0${seconds}` : seconds}
<div className="flex gap-10 justify-around">
<RunButton title="start" action={startTimer} />
<RunButton title="stop" color="red" action={stopTimer} />
<RunButton action={resetTimer} color="yellow" title="reset" />
</div>
</div>
);
};
export default RunTimer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
我还是不明白为什么你需要 Date.now() 来创建秒表。
有什么问题:
const RunTimer = () => {
const [time, setTime] = useState(0);
const timerInterval = useRef(null);
const startTimer = () => {
if (!timerInterval.current) {
timerInterval.current = setInterval(() => {
setTime((t) => t + 1000);
}, 1000);
}
};
const stopTimer = () => {
clearInterval(timerInterval.current);
timerInterval.current = null;
};
const resetTimer = () => {
setTime(0);
};
const seconds = Math.floor(time / 1000) % 60;
const minutes = Math.floor(time / 1000 / 60) % 60;
useEffect(() => {
return () => clearInterval(timerInterval.current);
}, []);
return (
<div className="text-6xl font-medium text-center">
{minutes < 10 ? `0${minutes}` : minutes}:
{seconds < 10 ? `0${seconds}` : seconds}
<div className="flex gap-10 justify-around">
<button title="start" onClick={startTimer}>
start
</button>
<button title="start" onClick={stopTimer}>
stop
</button>
<button title="start" onClick={resetTimer}>
reset
</button>
</div>
</div>
);
};
我试图制作一个秒表计数器,但是当我调用“startTimer”函数时,setInterval 函数在 setStartTime 之前触发(在我第二次单击开始按钮后触发)。
import React from "react";
import { useState, useRef } from "react";
import RunButton from "./RunButton";
const RunTimer = () => {
const [timerOn, setTimerOn] = useState(false);
const [startTime, setStartTime] = useState(0);
const [timerTime, setTimerTime] = useState(0);
const timerInterval = useRef(null);
const startTimer = () => {
setTimerOn(true);
setStartTime(Date.now() - timerTime);
timerInterval.current = setInterval(() => {
setTimerTime(Date.now() - startTime);
}, 1000);
};
const stopTimer = () => {
setTimerOn(false);
clearInterval(timerInterval);
};
const resetTimer = () => {
setStartTime(0);
setTimerTime(0);
};
let seconds = Math.floor(timerTime / 1000) % 60;
let minutes = Math.floor(timerTime / 1000 / 60) % 60;
return (
<div className="text-6xl font-medium text-center">
{minutes < 10 ? `0${minutes}` : minutes}:
{seconds < 10 ? `0${seconds}` : seconds}
<div className="flex gap-10 justify-around">
<RunButton title="start" action={startTimer} />
<RunButton title="stop" color="red" action={stopTimer} />
<RunButton action={resetTimer} color="yellow" title="reset" />
</div>
</div>
);
};
export default RunTimer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
我还是不明白为什么你需要 Date.now() 来创建秒表。
有什么问题:
const RunTimer = () => {
const [time, setTime] = useState(0);
const timerInterval = useRef(null);
const startTimer = () => {
if (!timerInterval.current) {
timerInterval.current = setInterval(() => {
setTime((t) => t + 1000);
}, 1000);
}
};
const stopTimer = () => {
clearInterval(timerInterval.current);
timerInterval.current = null;
};
const resetTimer = () => {
setTime(0);
};
const seconds = Math.floor(time / 1000) % 60;
const minutes = Math.floor(time / 1000 / 60) % 60;
useEffect(() => {
return () => clearInterval(timerInterval.current);
}, []);
return (
<div className="text-6xl font-medium text-center">
{minutes < 10 ? `0${minutes}` : minutes}:
{seconds < 10 ? `0${seconds}` : seconds}
<div className="flex gap-10 justify-around">
<button title="start" onClick={startTimer}>
start
</button>
<button title="start" onClick={stopTimer}>
stop
</button>
<button title="start" onClick={resetTimer}>
reset
</button>
</div>
</div>
);
};