#javascript #reactjs #setinterval #use-state
Вопрос:
В принципе, я пытался создать счетчик, который начинал отсчитывать количество секунд, как только я нажимал кнопку «Пуск», и прекращал отсчет, когда я нажимал кнопку «Стоп», и сохранял это в секундах.
Когда я нажимаю кнопку «Пуск», запускается функция handleStart, которая устанавливает начальную переменную в 1. Кроме того, setInterval начинает повторять (каждую секунду) функцию настройки, которая увеличивает секунду на единицу. Этот setInterval также имеет условный оператор, который очищает setInterval, когда start становится 0;
Когда я нажимаю кнопку «Стоп», запускается другая функция handleStop, устанавливающая начало на 0. Если выполняется setInterval, он должен увидеть, что сейчас значение start равно 0, и должен очистить setInterval, который должен прекратить обновление переменной/состояния sec. Но это не работает. Когда я регистрирую запуск, он все еще равен 1, даже после нажатия переменной stop. Если я регистрирую запуск в функции handleStop, он регистрируется как 0, но это не отражается в дальнейших инструкциях журнала функции handleStart. Кроме того, когда я комментирую setSec((prev)=> {return prev 1})
строку в функции handleStart, все работает нормально (setInterval очищается после нажатия кнопки «Стоп»), поэтому я предполагаю, что в функциональности useState есть что-то, чего я не понимаю. Может кто-нибудь сказать мне, что случилось?
export default function Bug() {
let start = 0
let [sec, setSec] = useState(0)
let repeat
function handleStart() {
start = 1
repeat = setInterval(() => {
setSec((prev) => { return prev 1 })
console.log(start);
if (start === 0) {
clearInterval(repeat)
}
}, 100);
}
function handleStop() {
start = 0
//clearInterval(repeat) //this clearInterval is not working either
}
return (
<div>
<p>{sec}</p>
<button onClick={handleStart}>Start</button>
<button onClick={handleStop}>Stop</button>
</div>
)
}
Извините, если на такой вопрос уже был дан ответ здесь. Я попытался найти аналогичный вопрос, но не смог его найти.
Комментарии:
1. зачем вам нужно очищать интервал внутри обратного
setInterval
вызова, если вы очищаете его внутриhandleStop
.2. Я пропустил один из них, чтобы прокомментировать. Но все равно, ни один из clearInterval не работает.
3.
repeat
повторно инициализируется при каждом рендеринге, поэтому после первого тика ссылка на интервал больше не сохраняется. Если вы хотите обработать это таким образом, либо используйте ссылку, очистите ее в обратном вызове, либо используйте жизненный цикл визуализации для управления состоянием таймера.4. Переместитесь
let repeat
в место за пределами вашего функционального компонента5. @devnull69, это не очень хорошее предложение. Компонент должен содержать соответствующую логику
Ответ №1:
Ваша repeat
переменная не сохраняется между визуализациями, поэтому каждый раз, когда вы вызываете setSec
ее, она повторно визуализируется.
Одним из вариантов было бы использовать ту же идею, что и переменная таймера, для хранения переменной повтора.
const Bug = () => {
const [sec, setSec] = useState(0)
const [repeat,setRepeat] = useState()
const handleStart = () => {
setRepeat(setInterval(() => {
setSec((prev) => { return prev 1 })
}, 1000));
}
const handleStop = () => {
clearInterval(repeat)
}
return (
<div>
<p>{sec}</p>
<button onClick={handleStart}>Start</button>
<button onClick={handleStop}>Stop</button>
</div>
)
}
ReactDOM.render(<Bug/>,document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<script>var { useReducer, useEffect, useState, useRef, useCallback } = React</script>
<div id="root"></div>
Комментарии:
1. Я думаю, что ссылка была бы здесь еще более уместной