【问题标题】:Timer App using React: setInterval is getting cleared after every render使用 React 的计时器应用程序:每次渲染后都会清除 setInterval
【发布时间】:2020-02-24 09:09:58
【问题描述】:

我正在尝试创建一个简单的计时器应用程序,该应用程序将在单击按钮时开始增加秒数。我正在使用反应挂钩来实现这一点。

import React, { useState } from 'react'

function Timer() {

  const [seconds, setSeconds] = useState(0);

  const startTimer = () => {
    let timerID = setInterval(setSeconds((prevState) => prevState + 1), 1000);
  };

  return (
    <>
      <p> Seconds {seconds}</p>

      <button onClick={startTimer}> Start Timer </button>
    </>
  );
}


export default Timer;

setInterval 函数在每次渲染后被清除。理想情况下,它应该继续运行,直到明确清除。 每次单击开始计时器按钮时,秒状态只会增加一次。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    setInterval 方法需要调用一个函数。您调用setSeconds,它立即将秒数增加1,但setInterval 不能再次调用它,因为它不是一个函数。用箭头函数包裹表达式:

    () => setSeconds((prevState) => prevState + 1)
    

    例子:

    const { useState, Fragment } = React;
    
    function Timer() {
    
      const [seconds, setSeconds] = useState(0);
    
      const startTimer = () => {
        let timerID = setInterval(
          () => setSeconds((prevState) => prevState + 1) // pass an arrow function that calls setSeconds
        , 100);
      }
    
      return (
        <Fragment>
          <p> Seconds {seconds}</p>
    
          <button onClick={startTimer}> Start Timer </button>
        </Fragment>
      )
    }
    
    
    ReactDOM.render(
      <Timer />,
      root
    )
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="root"></div>

    注意事项:

    1. 您应该将timerID 保存在引用中,以便清除它
    2. 每次单击“开始计时器”按钮时清除间隔(并将秒数设置为 0),这样您就不会有多个正在运行的计时器
    3. 使用useEffect清除组件卸载时的间隔

    【讨论】:

      【解决方案2】:
      1. setInterval 需要一个函数作为第一个参数
      2. 为避免内存泄漏,您需要清除之前的时间间隔

          import ReactDOM from "react-dom";
          import React, { useState, useEffect, useRef } from "react";
          
          function Timer() {
            const [seconds, setSeconds] = useState(0);
            const timerId = useRef(null);
          
            useEffect(() => {
              return () => stopTimer();
            }, []);
          
            const startTimer = () => {
              stopTimer();
              timerId.current = setInterval(
                () => setSeconds(prevState => prevState + 1),
                1000
              );
            };
          
            const stopTimer = () => {
              if (timerId.current != null) {
                clearInterval(timerId.current);
              }
            };
          
            return (
              <>
                <p> Seconds {seconds}</p>
                <button onClick={startTimer}> Start Timer </button>
              </>
            );
          }
          
          const rootElement = document.getElementById("root");
          ReactDOM.render(<Timer />, rootElement);
      <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>

      【讨论】:

        猜你喜欢
        • 2017-05-31
        • 1970-01-01
        • 1970-01-01
        • 2021-12-14
        • 2019-11-23
        • 2019-08-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多