Создание таймера в React

Простите меня, если это кажется слишком простым ... это первое, что я когда-либо делал в React, поэтому я просто пытаюсь осмыслить вещи. Я уже понимаю, что у меня должен быть меньший компонент, такой как кнопки, и отображать их с помощью реквизита и всего прочего (цель - провести рефакторинг позже!), Но в настоящее время мне трудно понять, как использовать метод setInterval для изменения состояния, и тогда прекратите это.

Я создаю таймер pomodoro, и общая идея заключается в том, что мое состояние поддерживает общее количество секунд, которые таймер должен был оставить. У меня есть еще одна функция, которая преобразует общее количество секунд в формат времени, который я хочу отобразить.

Моя борьба находится в моем методе startStop (), я бы хотел изменить состояние работы (таймер работает) на t / f, и это сработает, но я явно делаю что-то с помощью setInterval. Я хочу установить интервал (когда остается время) для изменения состояния каждую секунду на 1 секунду меньше. Когда я снова нажимаю кнопку, интервальный таймер останавливается, и текущее «состояние» оставшихся секунд будет таким же, поэтому, если вы снова нажмете кнопку, он просто снова запустит таймер.

Спасибо за помощь! (Все это отображается из приложения create-response-app, поэтому в моем github требуется больше: https://github.com/ryanmdoyle/web-pomodoro)

    import React, { Component } from "react ";

    class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sessionTimeEntry: 25, //in min
      breakTimeEntry: 5, //in min
      sessionRemainingSeconds: 1500, //in seconds
      breakRemainingSeconds: 300, //in seconds
      running: false,
      timerLabel: "Session"
    }
    this.addSession = this.addSession.bind(this);
    this.subSession = this.subSession.bind(this);
    this.addBreak = this.addBreak.bind(this);
    this.subBreak = this.subBreak.bind(this);
    this.startStop = this.startStop.bind(this);
    this.resetTimer = this.resetTimer.bind(this);
    this.formatMinutes = this.formatMinutes.bind(this);
  }

  addSession() { //adding and subtracting methods need to also chage the session remaining in seconds to mirrow the entry time if ever changed
    this.setState({
      sessionTimeEntry: this.state.sessionTimeEntry + 1,
      sessionRemainingSeconds: this.state.sessionRemainingSeconds + 60
    })
  }

  subSession() {
    this.setState({
      sessionTimeEntry: this.state.sessionTimeEntry - 1,
      sessionRemainingSeconds: this.state.sessionRemainingSeconds - 60

    })
  }

  addBreak() {
    this.setState({
      breakTimeEntry: this.state.breakTimeEntry + 1,
      breakRemainingSeconds: this.state.breakRemainingSeconds + 60
    })
  }

  subBreak() {
    this.setState({
      breakTimeEntry: this.state.breakTimeEntry - 1,
      breakRemainingSeconds: this.state.breakRemainingSeconds - 60
    })
  }

  startStop() {

    let timer;
    const status = this.state.running;

    switch (status) {
      case false:
        console.info("should start!")
        this.setState({
          running: true
        })

        while (this.state.breakRemainingSeconds > 0) {
          timer = setInterval(() => {
            this.setState({
              breakRemainingSeconds: this.state.breakRemainingSeconds - 1
            });
            console.info(this.state.breakRemainingSeconds);
          }, 1000)
        }

        break;
      case true:
        console.info("should stop")
        this.setState({
          running: false
        })
        clearInterval(timer)
        break;
      default:
        break;
    }

  }

  resetTimer() {
    this.setState({
      sessionTimeEntry: 25,
      breakTimeEntry: 5,
      sessionRemainingSeconds: 1500,
      breakRemainingSeconds: 300,
      running: false,
      timerLabel: "Session"
    })
  }

  formatMinutes(time) {
    let seconds = time;
    const minutes = (seconds % 60 === 0) ? ((seconds / 60) < 10 ? "0" + seconds / 60 : seconds / 60) : (Math.floor(seconds / 60) < 10 ? "0" + Math.floor(seconds / 60) : Math.floor(seconds / 60));
    seconds = (seconds % 60 === 0) ? "00" : ((seconds % 60 < 10) ? "0" + (seconds % 60) : seconds % 60)
    console.info(minutes + ":" + seconds);
    return minutes + ":" + seconds;
  }

  render() {
    return ( <
      div >
      <
      h1 > Pomodoro Clock < /h1> <
      h2 > {
        this.state.sessionTimeEntry
      } < /h2> <
      div id = 'timerContainer' >
      <
      h3 id = "session-label" > Session Time < /h3> <
      h3 id = "session-length" > {
        this.formatMinutes(this.state.sessionRemainingSeconds)
      } < /h3> <
      button onClick = {
        this.addSession
      }
      id = "session-increment" > ^ < /button> <
      button onClick = {
        this.subSession
      }
      id = "session-decrement" > v < /button> <
      /div> <
      div id = 'timerContainer' >
      <
      h3 id = "break-label" > Break Time < /h3> <
      h3 id = "break-length" > {
        this.state.breakTimeEntry
      } < /h3> <
      button onClick = {
        this.addBreak
      }
      id = "break-increment" > ^ < /button> <
      button onClick = {
        this.subBreak
      }
      id = "break-decrement" > v < /button> <
      /div> <
      div >
      <
      button onClick = {
        this.startStop
      }
      id = "start-stop" > Start / Stop < /button> <
      button onClick = {
        this.resetTimer
      }
      id = "reset" > Reset < /button> <
      /div> <
      /div>
    )
  }

}

export default App;

**************** ОБНОВИТЬ *****************

Во всем разобрался! Вот ссылка на рабочий код, чтобы увидеть его в действии.

https://codepen.io/ryanmdoyle/pen/vaxoaG

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
3 860
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете создать setInterval, который уменьшает breakRemainingSeconds на единицу каждую секунду, и сохранить идентификатор, возвращаемый setInterval, в экземпляре. Позже вы можете использовать clearInterval(this.timer), когда захотите остановить таймер.

startStop() {
  const { running } = this.state;

  if (running) {
    this.setState({
      running: false
    });
    clearInterval(this.timer);
  } else {
    this.setState({
      running: true
    });

    this.timer = setInterval(() => {
      this.setState(previousState => {
        return {
          breakRemainingSeconds: previousState.breakRemainingSeconds - 1
        };
      });
    }, 1000);
  }
}
Ответ принят как подходящий

Я думаю, проблема в вашей функции startStop. Удалите цикл while из вашей функции.

startStop() {
    const status = this.state.running;

    switch (status) {
        case false:
          console.info("should start!")
          this.setState({
              running: true
          })

          this.timer = setInterval(() => {
              this.setState({
                  breakRemainingSeconds: this.state.breakRemainingSeconds - 1
              });
              console.info(this.state.breakRemainingSeconds);
          }, 1000)
        }

        break;
        case true:
          console.info("should stop")
          this.setState({
            running: false
          }) 
          clearInterval(this.timer)
          break;
        default:
          break;
    }

}

Спасибо! Я смог понять это без цикла while. Это было частью проблемы.

Ryan 24.07.2018 22:08

Я предлагаю использовать такую ​​библиотеку, как moment. Просто установите его как зависимость: npm я реагирую момент, потому что JS может быть немного сложнее с датами и временем. В любом случае, вот функция, с которой вы можете начать. Я надеюсь, что это помогает. Я использовал ваш breakRemainingSeconds для демонстрации, но вы можете настроить его, чтобы добиться всего управления временем, которое вам может понадобиться в вашем компоненте.

    class Timer extends React.Component {
    constructor() {
    super();
    this.state = { 
    time: {}, 
    breakRemainingSeconds: 300
    };
    
    this.timer = 0;
    this.startTimer = this.startTimer.bind(this);
    this.countDown = this.countDown.bind(this);
  }

// Let's make some sense of JS date and time It can get a little bit tricky sometimes.
// So, what we're doing here is taking the values and converting it in hours minutes, seconds. 
// In the example below we are using minutes and seconds, but just in case we got hours in there too :)

    createTime(secs){
      let hours = Math.floor(secs / (60 * 60));
      let divisor_for_minutes = secs % (60 * 60);
      let minutes = Math.floor(divisor_for_minutes / 60);
      let divisor_for_seconds = divisor_for_minutes % 60;
      let seconds = Math.ceil(divisor_for_seconds);

    let timeObject = {
      "h": hours,
      "m": minutes,
      "s": seconds
    };
    return timeObject;
  }

  componentDidMount() {
 // Taking the starting point  -> breakRemainingSeconds <-
// Passing it as the parameter and setting the state's time object to it.
    let timeLeft = this.createTime(this.state.breakRemainingSeconds);
    this.setState({ time: timeLeft });
  }

// Check the current state and potentially (if != 0) start our main function 
  startTimer() {
    if (this.timer == 0) {
      this.timer = setInterval(this.countDown, 1000);
    }
  }

countDown() {
    // Remove one second, set state so a re-render happens.
    let seconds = this.state.breakRemainingSeconds - 1;
    this.setState({
      time: this.createTime(seconds),
      breakRemainingSeconds: seconds
    });
    
    // Check if we're at zero, and if so, clear the Interval
    if (seconds == 0) { 
      clearInterval(this.timer);
    }
  }

  render() {
    return(
      <div>
        <button 
                onClick = {this.startTimer} style = {{marginRight:'12px'}}>Let's Go</button>
        m: {this.state.time.m} s: {this.state.time.s}
      </div>
    );
  }
}

ReactDOM.render(<Timer/>, document.getElementById('container'));
    <script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
     <script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id = "container"></div>

Я поставилbuttonздесь, чтобы начать процесс, но если вы хотите запустить его после рендеринга компонента, просто введитеthis.startTimer();внутриcomponentDidMountжизненный цикл

Спасибо! было полезно увидеть другой способ сделать это. Я действительно пытался понять это без каких-либо дополнительных зависимостей времени / даты, но я думаю, что в реальной жизни я, вероятно, использовал бы это. Гораздо проще.

Ryan 24.07.2018 22:10

Другие вопросы по теме