vivo una temporizador segundos regresiva cuenta cronometro crear crea con javascript reactjs countdown

javascript - una - Temporizador de cuenta regresiva en Reaccionar



cuenta regresiva segundos jquery (4)

He visto muchos temporizadores de cuenta regresiva en JavaScript y quería que funcionara en React.

He tomado prestada esta función que encontré en línea:

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; };

Y luego he escrito este código yo mismo

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(); } };

Actualmente, al hacer clic en, se configurará el tiempo en pantalla en: Time Remaining: 1 m : 0 s Pero no se reduce a Time Remaining: 0 m : 59 s luego Time Remaining: 0 m : 58 s etc., etc.

Creo que necesito volver a llamar a la función con un parámetro diferente. ¿Cómo puedo hacer esto?

EDITAR: OLVIDÉ DE DECIR, ME GUSTARÍA LA FUNCIONALIDAD PARA PODER USAR SEGUNDOS A MINUTOS Y SEGUNDOS


El único inconveniente de setInterval es que puede ralentizar el hilo principal. Puede hacer un temporizador de cuenta regresiva utilizando requestAnimationFrame en requestAnimationFrame lugar para evitar esto. Por ejemplo, este es mi componente genérico de temporizador de cuenta regresiva:

class Timer extends Component { constructor(props) { super(props) // here, getTimeRemaining is a helper function that returns an // object with { total, seconds, minutes, hours, days } this.state = { timeLeft: getTimeRemaining(props.expiresAt) } } // Wait until the component has mounted to start the animation frame componentDidMount() { this.start() } // Clean up by cancelling any animation frame previously scheduled componentWillUnmount() { this.stop() } start = () => { this.frameId = requestAnimationFrame(this.tick) } tick = () => { const timeLeft = getTimeRemaining(this.props.expiresAt) if (timeLeft.total <= 0) { this.stop() // ...any other actions to do on expiration } else { this.setState( { timeLeft }, () => this.frameId = requestAnimationFrame(this.tick) ) } } stop = () => { cancelAnimationFrame(this.frameId) } render() {...} }


El problema está en su "este" valor. La función de temporizador no puede acceder al prop "estado" porque se ejecuta en un contexto diferente. Te sugiero que hagas algo como esto:

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

Como puede ver, he agregado un método de "enlace" a su función de temporizador. Esto permite al temporizador, cuando se le llama, acceder al mismo "esto" de su componente de reacción (este es el principal problema / mejora cuando se trabaja con javascript en general).

Otra opción es usar otra función de flecha:

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


setState cada segundo con los segundos restantes (cada vez que se llama al intervalo). Aquí hay un ejemplo:

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.state.seconds > 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>


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.state.seconds > 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>