Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Como eu poderia separar a função "regressiva" em um arquivo separado dentro da pasta utils?

Eu achei a ideia de separar funções utilitárias em uma pasta separada de onde elas podem ser importadas muito boa, como no caso da função que calcula o tempo em segundos utilizada pelo Cronômetro.

Eu tentei fazer isso com a função regressiva, mas não consegui. Como ela chama a setTempo e a finalizarTarefa pegando elas do escopo externo, eu precisaria passar essas funções como parâmetros da função regressiva se eu a separar em outro arquivo, mas a tipagem do TypeScript ficou dando erro.

O código que eu tentei fazer foi esse:

interface Params {

contador: number,

finalizarTarefa: () => void,

setTempo: (tempo: number) => void

}

export function regressiva({ contador = 0, finalizarTarefa, setTempo }: Params) {

if(contador === 0) finalizarTarefa();

setTimeout(() => {

if(contador > 0) {

setTempo(contador - 1);

return regressiva(contador - 1, finalizarTarefa, setTempo); // o erro está acontecendo nesta linha

}

}, 1000)

}

2 respostas
solução!

Fala Daniel, beleza?

Para fazer isso vou te dar 2 opções, a primeira é utilizando um callback e a segunda é criando um hook customizado:

  1. Callback 1.2. Pra fazer uma função com callback, você tem que passar a função setTempo e finalizar para a regressiva, para isso o código ficaria assim: ` import { Dispatch, SetStateAction } from "react";

export default function regressiva( contador: number = 0, setTempo: Dispatch<SetStateAction<number | undefined>>, finalizar: () => void ) { setTimeout(() => { if(contador > 0) { setTempo(contador - 1); return regressiva(contador - 1, setTempo, finalizar); } finalizar(); }, 1000) }

```
  1. hook customizado 2.1. Com o hook customizado fica bem interessante também, assim você pode tirar toda a responsabilidade do Cronômetro de manter o tempo, e deixa tudo em uma função separada! O hook customizado fica assim:

     import { useState } from "react";
    
     export default function useRegressiva(
       finalizar: () => void
     ) {
       const [tempo, setTempo] = useState(0);
    
       function regressiva() {
         setTempo(tempoAnterior => tempoAnterior - 1);
         setTimeout(() => {  
           if(tempo > 1) {
             return regressiva();
           }
           finalizar();
         }, 1000)
       };
    
       return {
         tempo,
         setTempo,
         regressiva
       }
     }

    E chamando o hook fica assim:

    export default function Cronometro({ selecionado, finalizarTarefa }: Props) {
    const { tempo, setTempo, regressiva } = useRegressiva(finalizarTarefa);
    
    useEffect(() => {
     if(selecionado?.tempo) {
       setTempo(tempoParaSegundos(selecionado.tempo));
     }
    },[selecionado, setTempo]);
    
    return (
     <div className={style.cronometro}>
       <p className={style.titulo}>Escolha um card e inicie o Cronômetro</p>
       <div className={style.relogioWrapper}>
         <Relogio tempo={tempo} />
       </div>
       <Botao onClick={() => selecionado?.tempo && regressiva()}>
         Começar!
       </Botao>
     </div>
    )
    }

As duas formas funcionam e tem propostas diferentes, vê qual você prefere e divirta-se! Caso você ainda não esteja acostumado com hooks customizado, te recomendo assistir esse curso aqui.

Bons estudos!

Obrigado pela resposta e pela sugestão de curso, já coloquei na lista de próximos!