2016-11-30 15 views
5

Я видел много таймеров обратного отсчета в JavaScript и хотел, чтобы один из них работал в React.Таймер обратного отсчета в реакторе

Я позаимствовал эту функцию я нашел в Интернете:

secondsToTime(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 obj = { 
     "h": hours, 
     "m": minutes, 
     "s": seconds 
    }; 
    return obj; 
    }; 

И тогда я написал этот код самого

initiateTimer =() => { 
    let timeLeftVar = this.secondsToTime(60); 
    this.setState({ timeLeft: timeLeftVar }) 
    }; 

    startTimer =() => { 
    let interval = setInterval(this.timer, 1000); 
    this.setState({ interval: interval }); 
    }; 

    timer =() => { 
    if (this.state.timeLeft >0){ 
     this.setState({ timeLeft: this.state.timeLeft -1 }); 
    } 
    else { 
     clearInterval(this.state.interval); 
     //this.postToSlack(); 
    } 
    }; 

В настоящее время OnClick будет установить время на экране: Time Remaining: 1 m : 0 s Но это не уменьшает его до Time Remaining: 0 m : 59 s, а затем Time Remaining: 0 m : 58 s и т. д.

Я думаю, мне нужно снова вызовите функцию с другим параметром. как я могу это сделать?

EDIT: Я забыл сказать, я хотел бы, чтобы ФУНКЦИОНАЛЬНОСТИ ТАК ЧТО Я МОГУ ИСПОЛЬЗОВАТЬ НА ПРОТОКОЛ СЕКУНД & СЕКУНД

+0

Одним из [РЕАКТ примеры документации] (https://facebook.github.io/react/docs/state-and-lifecycle.html) это часы что обновляет себя, похоже, было бы довольно полезно ... –

+0

@TJCrowder это полу полезно. они просто получают время, хотя могут вернуть его через componentDidMount, тогда как я хочу только извлечь секунды и минуты из исходной позиции. –

+0

Возможно, вы могли бы поставить runnable [mcve] в вопрос, используя Stack Snippets, который [поддерживает React и JSX] (http://meta.stackoverflow.com/questions/338537/how-do-i-create-a-reactjs-stack-snippet-with-jsx-support), чтобы мы могли видеть проблему в действии. –

ответ

14

Вы должны setState каждую секунду с остающимся секунды (каждый раз, когда интервал называется). Вот пример:

class Example extends React.Component { 
 
    constructor() { 
 
    super(); 
 
    this.state = { time: {}, seconds: 5 }; 
 
    this.timer = 0; 
 
    this.startTimer = this.startTimer.bind(this); 
 
    this.countDown = this.countDown.bind(this); 
 
    } 
 

 
    secondsToTime(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 obj = { 
 
     "h": hours, 
 
     "m": minutes, 
 
     "s": seconds 
 
    }; 
 
    return obj; 
 
    } 
 

 
    componentDidMount() { 
 
    let timeLeftVar = this.secondsToTime(this.state.seconds); 
 
    this.setState({ time: timeLeftVar }); 
 
    } 
 

 
    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.seconds - 1; 
 
    this.setState({ 
 
     time: this.secondsToTime(seconds), 
 
     seconds: seconds, 
 
    }); 
 
    
 
    // Check if we're at zero. 
 
    if (seconds == 0) { 
 
     clearInterval(this.timer); 
 
    } 
 
    } 
 

 
    render() { 
 
    return(
 
     <div> 
 
     <button onClick={this.startTimer}>Start</button> 
 
     m: {this.state.time.m} s: {this.state.time.s} 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<Example/>, document.getElementById('View'));
<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="View"></div>

+0

это хорошо выглядит. Одна проблема заключается в том, что она не останавливается на 0 и идет на минус, хотя? исправьте это, и я его приму;) –

+0

Ну, это похоже на то, что у вас было в исходном коде. Проверьте, осталось ли несколько секунд, а затем сделайте 'clearInterval'. Обновлен мой ответ. –

+0

Вы также можете сделать гораздо больше оптимизаций, таких как сброс таймера, пауза и т. Д., но вопрос был нацелен на то, как отсчитывать и отражать это в рендеринге. –

1

проблема в вашей «это» значение. Функция таймера не может получить доступ к опоре состояния, потому что выполняется в другом контексте. Я предлагаю вам сделать что-то вроде этого:

... 
startTimer =() => { 
    let interval = setInterval(this.timer.bind(this), 1000); 
    this.setState({ interval }); 
}; 

Как вы можете видеть, я добавил метод «привязки» к вашей функции таймера. Это позволяет таймеру при вызове обращаться к тому же «этому» из вашего реагирующего компонента (это основная проблема/улучшение при работе с javascript в целом).

Другой вариант заключается в использовании другой функции стрелка:

startTimer =() => { 
    let interval = setInterval(() => this.timer(), 1000); 
    this.setState({ interval }); 
}; 
+0

Хорошо-пятнистый! .... –

+0

ах да, я забыл связать. это не решает мою главную проблему, не считая? –