首页 > 解决方案 > 不确定如何在更改导航选项卡时停止计时器重置

问题描述

Codesandbox我有一个应用程序,它记录用户在应用程序内页面上的屏幕时间。但是,当我在导航栏选项卡(“关于”和“时间”)之间单击时,计时器会重置。在此处输入图像描述

我不希望它重置。我希望它在我更改导航栏选项卡后暂停,并在我返回同一选项卡时恢复。我尝试使用 setInterval 而不是 setTimeout 但没有任何变化。

关于.js

  import React, { useState, useEffect } from 'react';

  const About = () => {
    const [time, setTime] = useState({
      seconds: 0,
      minutes: 0,
      hours: 0,
    });

    useEffect(() => {
      let isCancelled = false;

      const advanceTime = () => {
        setInterval(() => {
          let nSeconds = time.seconds;
          let nMinutes = time.minutes;
          let nHours = time.hours;

          nSeconds++;

          if (nSeconds > 59) {
            nMinutes++;
            nSeconds = 0;
          }
          if (nMinutes > 59) {
            nHours++;
            nMinutes = 0;
          }
          if (nHours > 24) {
            nHours = 0;
          }

          !isCancelled && setTime({ seconds: nSeconds, minutes: nMinutes, hours: nHours });
        }, 1000);
      };
      advanceTime();

      return () => {
        //final time:
        console.log(time);
        isCancelled = true;
      };
    }, [time]);

    return (
      <div>
        <p>
          {`
            ${time.hours < 10 ? '0' + time.hours : time.hours} :
            ${time.minutes < 10 ? '0' + time.minutes : time.minutes} :
            ${time.seconds < 10 ? '0' + time.seconds : time.seconds}
          `}
        </p>
      </div>
    );
  }

export default About; 

时间.js

 import React, { useState, useEffect } from 'react';

  const Time = () => {
    const [time, setTime] = useState({
      seconds: 0,
      minutes: 0,
      hours: 0,
    });

    useEffect(() => {
      let isCancelled = false;

      const advanceTime = () => {
        setInterval(() => {
          let nSeconds = time.seconds;
          let nMinutes = time.minutes;
          let nHours = time.hours;

          nSeconds++;

          if (nSeconds > 59) {
            nMinutes++;
            nSeconds = 0;
          }
          if (nMinutes > 59) {
            nHours++;
            nMinutes = 0;
          }
          if (nHours > 24) {
            nHours = 0;
          }

          !isCancelled && setTime({ seconds: nSeconds, minutes: nMinutes, hours: nHours });
        }, 1000);
      };
      advanceTime();

      return () => {
        //final time:
        console.log(time);
        isCancelled = true;
      };
    }, [time]);

    return (
      <div>
        <p>
          {`
            ${time.hours < 10 ? '0' + time.hours : time.hours} :
            ${time.minutes < 10 ? '0' + time.minutes : time.minutes} :
            ${time.seconds < 10 ? '0' + time.seconds : time.seconds}
          `}
        </p>
      </div>
    );
  }

export default Time;

应用程序.js

import React from 'react';
import logo from './logo.svg';
import './App.css';
import Nav from './component/Nav';
import About from './component/About';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import Time from './component/Time';

function App() {
  return (
   <Router>
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div>
          <Nav />
           <Switch>
            <Route path = "/about" exact component = {About}/>
            <Route path = "/time" exact component = {Time}/>
          </Switch>
        </div>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
   </Router>
  );
}


export default App; 

标签: javascriptreactjs

解决方案


这只是您需要做的事情的要点。当您导航到另一条路线并返回时,组件将被重新渲染。正因为如此,他们的状态将不复存在。

要维护状态,您可以将您的状态“提升”到父组件。这意味着不是您AboutTime组件管理它们自己的状态,而是管理它们的App两个状态。

这看起来像这样:

function App() {
    const [time, setTime] = useState({
        seconds: 0,
        minutes: 0,
        hours: 0,
    });

    const [isAboutTimerOn, setIsAboutTimerOn] = useState(false)

    const advanceTime = () => {
        setIsAboutTimerOn(true)
        setInterval(() => {
            let nSeconds = time.seconds;
            let nMinutes = time.minutes;
            let nHours = time.hours;

            nSeconds++;

            if (nSeconds > 59) {
                nMinutes++;
                nSeconds = 0;
            }
            if (nMinutes > 59) {
                nHours++;
                nMinutes = 0;
            }
            if (nHours > 24) {
                nHours = 0;
            }

            isAboutTimerOn && setTime({ seconds: nSeconds, minutes: nMinutes, hours: nHours });
        }, 1000);
    };



    const startTime = () => {
        advanceTime()
    }

    const stopTime = () => {
        setIsAboutTimerOn(false)
    }

    return (
        <Router>
            <div className="App">
                <Nav />
                <Switch>
                    <Route path="/about" exact component={() => <About startTime={startTime} stopTime={stopTime} time={time}/>}/> // pass props
                </Switch>
            </div>
        </Router>
    );
}

您的用例的逻辑可能不正确,但问题与状态管理有关

由于您要管理两种不同的状态,因此您的代码将更加复杂。不过,您应该能够使你们中的一些逻辑可重用。

然后您的子组件将如下所示:

const About = ({ time, startTime, stopTime }) => {

    useEffect(() => {
        startTime()

        return () => {
            stopTime()
        }

    }, [startTime, stopTime])


    return (
        <div>
            <p>
                {`
            ${time.hours < 10 ? '0' + time.hours : time.hours} :
            ${time.minutes < 10 ? '0' + time.minutes : time.minutes} :
            ${time.seconds < 10 ? '0' + time.seconds : time.seconds}
          `}
            </p>
        </div>
    );
}

推荐阅读