|Thalles Bastos
Seguimos nosso tutorial de como criar um Pomodoro Timer em React. Para quem chegou direto nesse post aqui está o primeiro onde criamos a estrutura inicial dando uma identidade para nossa aplicação:
Parte 1 - Tutorial React Pomodoro - Criando a estrutura inicial
Abaixo teremos os dois principais arquivos do nosso app, um deles é o App.js onde ficarão nossas funções e o outro é o pomodoro.js, o componente que monta a estrutura.
Usaremos dois áudios nessa aplicação, um é o DingDong.mp3 para sinalizar quando o timer acabar e o outro o Click.mp3 para o início da contagem. Clique nos links para baixar os arquivos e coloque na pasta /public do projeto.
Código dos arquivos
Abaixo temos os dois principais arquivos do app com as linhas comentadas. Após ler e entender o que acontece no código você pode copiar e colar nos arquivos do seu projeto. Eles estão com a versão final do timer.
App.js
import React, { useState, useRef, useEffect, useMemo } from 'react'
import Pomodoro from './components/pomodoro';
function App() {
// Definição dos estados que usaremos e useRef() para os áudios
const Ref = useRef(null);
const [timer, setTimer] = useState('25:00');
const [timerActive, setTimerActive] = useState(false);
const [timerEnd, setTimerEnd] = useState();
const [textIniciar, setTextIniciar] = useState('Iniciar');
const [textMinutes, setTextMinutes] = useState('25');
// criando os arquivos de áudio que usaremos
const audioClick = useMemo(() => new Audio('/click.mp3'), []);
const audioDingDong = useMemo(() => new Audio('/ding-dong.mp3'), []);
// calculo do tempo restante para o final do timer
const getTimeRemaining = (e) => {
const total = Date.parse(e) - Date.parse(new Date());
const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor((total / 1000 / 60) % 60);
return {
total, minutes, seconds
};
}
// define o valor do timer em minutos, exemplo: 25:00
const startTimer = (e) => {
let { total, minutes, seconds } = getTimeRemaining(e);
if (total >= 0) {
setTimer((minutes > 9 ? minutes : '0' + minutes) + ':' + (seconds > 9 ? seconds : '0' + seconds))
}
}
// ao clicar em iniciar/retomar rodamos esta função
const initTimer = (e) => {
audioClick.play();
// caso seja para iniciar/retomar seta o timer como ativo e chama
// a função clearTimer() para limpar e criar o contador do timer
if(textIniciar === 'Iniciar' || textIniciar === 'Retomar'){
setTextIniciar('Parar');
setTimerActive(true);
clearTimer(getDeadTime());
} else {
// caso seja para parar a contagem gravamos o tempo que falta para
// acabar o timer e encerramos/limpamos o contador com clearInterval()
setTextIniciar('Retomar')
setTimerActive(false)
const diferenca = Date.parse(timerEnd) - Date.parse(new Date())
const seconds = Math.floor((diferenca / 1000) % 60)
const minutes = Math.floor((diferenca / 1000 / 60) % 60)
setTimer((minutes > 9 ? minutes : '0' + minutes) + ':' + (seconds > 9 ? seconds : '0' + seconds))
if (Ref.current) clearInterval(Ref.current)
}
}
// função que limpa timers existentes e cria o contador
const clearTimer = (e) => {
if(textIniciar === 'Iniciar'){
if (Ref.current) clearInterval(Ref.current)
}
const id = setInterval(() => {
setTimerEnd(e)
startTimer(e)
const diferenca = Date.parse(e) - Date.parse(new Date())
const seconds = Math.floor((diferenca / 1000) % 60)
const minutes = Math.floor((diferenca / 1000 / 60) % 60)
document.title = minutes+':'+seconds+' Pomodoro Timer - Otimize seu tempo';
// caso o timer tenha chegado no final, limpamos o contador
// e damos play no áudio que sinaliza que finalizou
if(Date.parse(new Date()) === Date.parse(e)){
if (Ref.current) clearInterval(Ref.current)
setTimer((textMinutes > 9 ? textMinutes : '0' + textMinutes) + ':00')
setTimerActive(false)
setTextIniciar('Iniciar')
audioDingDong.play()
}
}, 1000)
Ref.current = id
}
// verifica quando tempo já se passou no timer
const getDeadTime = () => {
let deadline = new Date()
deadline.setMinutes(deadline.getMinutes() + parseInt(textMinutes))
deadline.setSeconds(deadline.getSeconds() + 0)
return deadline
}
// caso o usuário mude o tempo do timer, seta o novo tempo e reinicia
useEffect(() => {
setTimer((textMinutes > 9 ? textMinutes : '0' + textMinutes) + ':00')
}, [textMinutes]);
// ao clicar em resetar, limpamos o contador e setamos o valor do timer
const resetTimer = () => {
setTimerActive(false)
setTimer((textMinutes > 9 ? textMinutes : '0' + textMinutes) + ':00')
setTextIniciar('Iniciar')
document.title = 'Pomodoro Timer - Otimize seu tempo'
if (Ref.current) clearInterval(Ref.current)
}
// chama nosso componente que monta o template do timer passando as propriedades necessárias
return (
<div className="App">
<Pomodoro
timer={timer}
initTimer={initTimer}
resetTimer={resetTimer}
timerActive={timerActive}
textIniciar={textIniciar}
textMinutes={textMinutes}
setTextMinutes={setTextMinutes}
/>
</div>
);
}
export default App;
/components/pomodoro.js
import React from 'react'
function Pomodoro(props) {
const { timer, initTimer, resetTimer, timerActive, textIniciar, textMinutes, setTextMinutes } = props;
const handleChange = event => {
resetTimer()
const min = 1
const max = 60
const value = Math.max(min, Math.min(max, Number(event.target.value)))
setTextMinutes(value)
};
return (
<div>
<div className='container'>
<h1>Pomodoro Timer</h1>
<div className="top">
<p>Vou focar durante </p>
<input
type="number"
maxLength="60"
value={textMinutes}
onChange={handleChange}
/>
<p>minutos</p>
</div>
<div className='timerPomo'>{timer}</div>
<div className='flexButtons'>
<button className={timerActive ? "buttonActive" : ""} onClick={initTimer}>{textIniciar}</button>
<button onClick={resetTimer}>Resetar</button>
</div>
</div>
<div className="shape-divider shape-divider-bottom">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 2000 245" preserveAspectRatio="xMinYMin">
<path fill="#FFF" opacity="0.5" d="M2028.47,246.15v-39.09C1945.6,199.68,1869.96,195.8,1803,194c-71.99-1.93-137.53-4.37-225,1 c-88.04,5.4-120.19,13.36-233,19c-55.14,2.76-102.19,5-165,3c-37.5-1.2-102.55-4.6-200-19c-89.42-13.21-145.61-26.73-276-57 C520.19,98.33,428.29,76.99,402,72C243.75,41.93,118.41,28.67,37,22c-26.77-2.19-49.49-3.73-66.33-4.77v229.03h2057.82 C2028.48,246.22,2028.47,246.19,2028.47,246.15z"></path>
<path fill="#FFF" d="M1816,212c-58.78-4.11-116.63-8.07-195-9c-43.43-0.51-105.81-1.13-187,4c-33.73,2.13-29.27,2.64-127,10 c-86.52,6.52-110.13,7.64-137,8c-11.31,0.15-53.81,0.58-110-3c-54.49-3.47-108.08-9.83-185-23c-69.21-11.85-114.89-21.96-202-41 c-262.93-57.46-291.75-62.62-318-67C229.24,70,155.97,65.58,121,64C60.05,61.24,8.67,62.27-28.77,63.95v187.41H2028V232 C1943.49,221.98,1871.42,215.88,1816,212z"></path>
</svg>
</div>
</div>
)
}
export default Pomodoro
Após adicionar o novo código nos arquivos existentes, rode a aplicação para ver as funções do timer em ação, dentro da pasta do projeto execute no terminal: $ npm start
Seguimos para a próxima etapa de como criar uma aplicação em React onde iremos publicar a aplicação no Heroku, salvar o projeto no Github e LinkedIn. Próxima parte:
-
Parte 3 - Tutorial React Pomodoro - Github e LinkedIn
-
DiversificaDev - Oferecendo mentoria gratuita para iniciantes em tecnologia e programação para estimular a diversidade na área além de soluções digitais como criação de sites, gestão mídias sociais, estratégias de marketing e otimização de sites SEO.
Nenhum comentário
Comentar