简体   繁体   English

如何在 React-hooks 中创建计时器

[英]How to create timer in React-hooks

How i can create animated timer using React-hooks我如何使用 React-hooks 创建动画计时器

Here is complete code what i had tried这是我尝试过的完整代码

Basically i was trying Displays the progress of time remaining as an animated ring.基本上我正在尝试将剩余时间的进度显示为动画环。 But somehow i am getting failed in it但不知何故我失败了

I just followed this blog for creating animated timer https://css-tricks.com/how-to-create-an-animated-countdown-timer-with-html-css-and-javascript/我刚刚关注这个博客来创建动画计时器https://css-tricks.com/how-to-create-an-animated-countdown-timer-with-html-css-and-javascript/

  function setRemainingPathColor(timeLeft) {
    const { alert, warning, info } = COLOR_CODES;
    console.log(dataFromDiv);
    if (timeLeft <= alert.threshold) {
      dataFromDiv.current
        .querySelectorAll("base-timer-path-remaining")
        .classList.remove(warning.color);
      dataFromDiv.current
        .querySelectorAll("base-timer-path-remaining")
        .classList.add(alert.color);
    } else if (timeLeft <= warning.threshold) {
      dataFromDiv.current
        .querySelectorAll("base-timer-path-remaining")
        .classList.remove(info.color);
      dataFromDiv.current
        .querySelectorAll("base-timer-path-remaining")
        .classList.add(warning.color);
    }
  }

  React.useEffect(() => {
    let timer;
    let timePassed = 0;
    let timeLeft;
    timer = counter > 0 && setTimeout(() => setCounter(counter - 1), 1000);
    timePassed = timePassed += 1;
    timeLeft = counter - timePassed;
    setRemainingPathColor(timeLeft);
    return () => {
      if (timer) {
        clearTimeout(timer);
      }
    };
  }, [counter]);

The error you were getting is because dataFromDiv.current.querySelectorAll(...) was always returning undefined because dataFromDiv.current was a reference to div#base-timer-path-remaining which is the element you wanted to modify.您收到的错误是因为dataFromDiv.current.querySelectorAll(...)总是返回 undefined 因为dataFromDiv.current是对div#base-timer-path-remaining的引用,这是您要修改的元素。 So, your code would work fine by just removing .querySelectorAll(...) .因此,只需删除.querySelectorAll(...) ,您的代码就可以正常工作。

However, there are some better ways to structure your code:但是,有一些更好的方法来构建您的代码:

Instead of doing direct dom manipulations, it's easier in this case to just figure out which color you want using useMemo to set up derived data based on the counter value.在这种情况下,不是直接进行 dom 操作,而是更容易地确定您想要使用哪种颜色使用useMemo根据计数器值设置派生数据。

You can also use an interval instead of a timer as it's easier to work with and a little bit cleaner.您还可以使用间隔而不是计时器,因为它更易于使用且更简洁。 This also uses the updater function form of setCounter so that the effect doesn't need to have counter in the dependencies.这也使用了 setCounter 的更新程序 function 形式,因此效果不需要在依赖项中有counter

I also added a reset button to my example below so you don't have to re-run it every time.我还在下面的示例中添加了一个重置按钮,因此您不必每次都重新运行它。

  const pathColor = React.useMemo(() => {
    const { alert, warning, info } = COLOR_CODES;
    if (counter <= alert.threshold) {
      return alert.color;
    } else if (counter <= warning.threshold) {
      return warning.color;
    } else {
      return info.color;
    }
  }, [counter]);

  React.useEffect(() => {
    const timerId = setInterval(() => {
      setCounter(counter => {
        if (counter <= 0) {
          clearInterval(timerId);
          return counter;
        }
        return counter - 1;
      });
    }, 1000);
    return () => {
      clearInterval(timerId);
    };
  }, [timerReset]); // this timerReset is to make sure that the interval starts off again whenever the reset button is pressed.

This line is simply a way to force a re-render.这条线只是一种强制重新渲染的方法。 The reducer function x=>x+1 increments the timerReset value whenever dispatch (renamed to resetTimer ) is called.每当调用 dispatch(重命名为resetTimer )时,reducer function x=>x+1都会增加timerReset的值。 And then I use timerReset to force the effect to re-run in order to start the interval again (if it stopped)然后我使用timerReset强制重新运行效果以再次开始间隔(如果它停止了)

  const [timerReset, resetTimer] = React.useReducer(x => x + 1, 0);

 const padTime = time => { return String(time).length === 1? `0${time}`: `${time}`; }; const format = time => { const minutes = Math.floor(time / 60); const seconds = time % 60; return `${minutes}:${padTime(seconds)}`; }; const WARNING_THRESHOLD = 10; const ALERT_THRESHOLD = 5; const COLOR_CODES = { info: { color: "green" }, warning: { color: "orange", threshold: WARNING_THRESHOLD }, alert: { color: "red", threshold: ALERT_THRESHOLD } }; function App() { const [counter, setCounter] = React.useState(20); const [timerReset, resetTimer] = React.useReducer(x => x + 1, 0); const pathColor = React.useMemo(() => { const { alert, warning, info } = COLOR_CODES; if (counter <= alert.threshold) { return alert.color; } else if (counter <= warning.threshold) { return warning.color; } else { return info.color; } }, [counter]); React.useEffect(() => { const timerId = setInterval(() => { setCounter(counter => { if (counter <= 0) { clearInterval(timerId); return counter; } return counter - 1; }); }, 1000); return () => { clearInterval(timerId); }; }, [timerReset]); return ( <div className="App"> <div className="base-timer"> <svg className="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" > <g className="base-timer__circle"> <circle className="base-timer__path-elapsed" cx="50" cy="50" r="45" /> <path id="base-timer-path-remaining" className={`base-timer__path-remaining ${pathColor}`} d=" M 50, 50 m -45, 0 a 45,45 0 1,0 90,0 a 45,45 0 1,0 -90,0 " /> </g> </svg> <span id="base-timer-label" className="base-timer__label"> {format(counter)} </span> </div> <button onClick={() => { setCounter(20); resetTimer(); }} > reset timer </button> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, rootElement );
 /* Sets the containers height and width */.base-timer { position: relative; height: 300px; width: 300px; } /* Removes SVG styling that would hide the time label */.base-timer__circle { fill: none; stroke: none; } /* The SVG path that displays the timer's progress */.base-timer__path-elapsed { stroke-width: 7px; stroke: grey; }.base-timer__path-remaining { stroke-width: 7px; stroke-linecap: round; transform: rotate(90deg); transform-origin: center; transition: 1s linear all; fill-rule: nonzero; stroke: currentColor; }.base-timer__path-remaining.green { color: rgb(65, 184, 131); }.base-timer__path-remaining.orange { color: orange; }.base-timer__path-remaining.red { color: red; }.base-timer__label { position: absolute; width: 300px; height: 300px; top: 0; display: flex; align-items: center; justify-content: center; font-size: 48px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script> <div id="root"></div>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Jest和react-testing-library中使用react-hook - How to use react-hooks with Jest and react-testing-library React - 如何在 React-Hooks 中隐藏其他元素时显示一个元素 - React - How to show an element while hiding the others in React-Hooks React-Hooks:如何调用 useState 返回的 function - React-Hooks: How to call a function returned by useState 如何在 react-hooks 中更新初始值(几个数据)? - How to updating initial values (several data) in react-hooks? 如何使用 object 数组的 React-hooks 设置状态() - How to setState() using React-hooks of array of object Reactjs:如何在分页中保留选中的项目state? React-hooks - Reactjs: how to keep a selected item state in the pagination? React-hooks 如何使用react-hooks更改像redux这样的变量的值? - How to change value of variable like redux but with react-hooks? 如何在 React-Hooks 中先运行 useEffect 部分? - How to run useEffect part first in React-Hooks? 如何在React中使用钩子实现componentDidMount以使其符合EsLint规则“ react-hooks / exhaustive-deps”:“ warn”? - How to implement componentDidMount with hooks in React to be in line with the EsLint rule “react-hooks/exhaustive-deps”: “warn”? React挂钩:如何使用react-hooks / exhaustive-deps规则在没有无限循环的情况下读取和更新挂钩中的状态 - React hooks: How to read & update state in hooks without infinite loops with react-hooks/exhaustive-deps rule
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM