Usando os Hooks no Typescript

Usando os Hooks no Typescript

Hoje, você irá aprender a fazer o uso dos hooks mais famosos do React usando o Typescript:

  • useState
  • useEffect
  • useCallback
  • useRef
  • useMemo
  • useContext

Vamos nessa? 😉

Usando useState com Typescript

No React, usamos o comando useState para controlar determinado estado da nossa aplicação, o que significa dizer que estamos controlando uma determinada informação que esta sendo mostrada para o usuário.

Para mais informações sobre o funcionamento do useState no React, acesse este link.

Como nós já vimos na lição passada, usamos o useState dentro dos nossos componentes da seguinte forma:

InformacoesEstados > index.tsx:  

import React, { useState } from 'react';

const InformacoesEstados: React.FC = () => {
 // Definindo os estados usando useState
 const [nome, setNome] = useState<string>('João');
 const [idade, setIdade] = useState<number>(30);
 const [humano, setHumano] = useState<boolean>(true);
 const [caracteristicas, setCaracteristicas] = useState<{
 altura: number;
 peso: number;
 cor: string;
 }>({
 altura: 1.80,
 peso: 75,
 cor: 'azul',
 });
 const [numerosDaSorte, setNumerosDaSorte] = useState<number[]>([7, 13, 21]);

 // Renderizando o componente
 return (
 <div>
 <h1>Informações</h1>
 <p><strong>Nome:</strong> {nome}</p>
 <p><strong>Idade:</strong> {idade}</p>
 <p><strong>Humano:</strong> {humano ? 'Sim' : 'Não'}</p>
 <p><strong>Características:</strong></p>
 <ul>
 <li><strong>Altura:</strong> {caracteristicas.altura} m</li>
 <li><strong>Peso:</strong> {caracteristicas.peso} kg</li>
 <li><strong>Cor:</strong> {caracteristicas.cor}</li>
 </ul>
 <p><strong>Números da Sorte:</strong></p>
 <ul>
 {numerosDaSorte.map((numero, index) => (
 <li key={index}>{numero}</li>
 ))}
 </ul>
 </div>
 );
};

export default InformacoesEstados;

Como cada uma das variáveis acima está conectada a um estado, podemos alterar esses estados tranquilamente por meio do comando setState() de dentro de uma função.

InformacoesEstados > index.tsx:

import React, { useState } from 'react';

const InformacoesEstados: React.FC = () => {
 // Definindo os estados usando useState
 const [nome, setNome] = useState<string>('João');
 const [idade, setIdade] = useState<number>(30);
 const [humano, setHumano] = useState<boolean>(true);
 const [caracteristicas, setCaracteristicas] = useState<{
 altura: number;
 peso: number;
 cor: string;
 }>({
 altura: 1.80,
 peso: 75,
 cor: 'azul',
 });
 const [numerosDaSorte, setNumerosDaSorte] = useState<number[]>([7, 13, 21]);

 // Função para mudar o nome de João para Maria
 const mudarNomeParaMaria = () => {
 setNome('Maria');
 };

 // Renderizando o componente
 return (
 <div>
 <h1>Informações</h1>
 <p><strong>Nome:</strong> {nome}</p>
 <p><strong>Idade:</strong> {idade}</p>
 <p><strong>Humano:</strong> {humano ? 'Sim' : 'Não'}</p>
 <p><strong>Características:</strong></p>
 <ul>
 <li><strong>Altura:</strong> {caracteristicas.altura} m</li>
 <li><strong>Peso:</strong> {caracteristicas.peso} kg</li>
 <li><strong>Cor:</strong> {caracteristicas.cor}</li>
 </ul>
 <p><strong>Números da Sorte:</strong></p>
 <ul>
 {numerosDaSorte.map((numero, index) => (
 <li key={index}>{numero}</li>
 ))}
 </ul>
 <button onClick={mudarNomeParaMaria}>Mudar Nome para Maria</button>
 </div>
 );
};

export default InformacoesEstados;

Note que ao clicar no botão [Mudar Nome para Maria], será acionado uma função chamada mudarNomeParaMaria(), que por sua vez, é responsável por alterar o valor do estado nome.

E é dessa forma que usamos o useState em conjunto com o ReactTS 🙃

Lembrando que podemos criar estados que armazenam objetos, variáveis, funções, classes e etc... basta apenas que você siga os ensinamentos da lição de estados.

Usando o UseEffect com Typescript

No caso do hook useEffect, a sua utilização não se difere muito daquilo que estamos acostumados a fazer.

Para mais informações sobre o funcionamento do useEffect no React, acesse este link

Para testarmos o seu uso, vamos criar um novo componente chamado de Efeito.

Efeito > index.jsx:

import React, { useEffect } from 'react';

interface EfeitoProps {
 mensagem: string;
}

const Efeito: React.FC<EfeitoProps> = ({ mensagem }) => {
 useEffect(() => {
 console.log(`Componente montado ou a mensagem mudou: ${mensagem}`);
 
 // Esta função é chamada quando o componente é desmontado
 return () => {
 console.log('Componente desmontado');
 };
 }, [mensagem]); // Dependência: o useEffect será chamado sempre que a prop 'mensagem' mudar

 return (
 <div>
 <h1>{mensagem}</h1>
 </div>
 );
};

export default Efeito;

Note que a sintaxe do useEffect permaneceu a mesma com aquela que já estamos acostumados, ou seja, nada mudou.

Lembrando que se você for delclarar alguma lógica dentro do useEffect, não se esqueça de fazer isso usufruindo da tipagem do Typescript.

Usando o useCallback com Typescript

Usamos o useCallback para salvar na memória da nossa aplicação uma versão memoizada de uma determinada função, o que ajuda a otimizar o desempenho das nossas aplicações.

Para mais informações sobre o funcionamento do useCallback no React, acesse este link.   

Para testarmos o seu funcionamento, que tal criar um componente que representa um contador?

Contador > index.tsx:

import React, { useCallback, useState } from 'react';

const Contador: React.FC = () => {
 const [count, setCount] = useState<number>(0);

 // Função de incremento memorada com useCallback
 const incrementar = useCallback(() => {
 setCount(prevCount => prevCount + 1);
 }, []); // Dependências vazias, a função só será criada uma vez

 return (
 <div>
 <p>Contador: {count}</p>
 <button onClick={incrementar}>Incrementar</button>
 </div>
 );
};

export default Contador;

Note que estamos fazendo o uso do useState para armazenar a contagem do estado na nossa aplicação.

Já o useCallback permanece com a mesma sintaxe daquela que conhecemos antes.

Usando o useRef com Typescript

O useRef é usado para armazenar a referência de um elemento DOM, ou quem sabe, um valor mutável que não causa a re-renderização do componente quando este for alterado.

Para mais informações sobre o funcionamento do useRef no React, acesse este link.     

Para testarmos ele em conjunto com o Typescript, vamos criar um novo componente chamado de FocoInput.

FocoInput > index.tsx:

import React, { useRef, useEffect } from 'react';

const FocoInput: React.FC = () => {
 const inputRef = useRef<HTMLInputElement>(null);

 useEffect(() => {
 if (inputRef.current) {
 inputRef.current.focus();
 }
 }, []);

 return <input ref={inputRef} type="text" />;
};

export default FocoInput;

No caso do comando acima, fizemos o uso do useRef, onde precisamos declarar o tipo de valor que ele irá controlar, que no caso, é um elemento do tipo <Input> (HTMLInputElement).

Além disso, fizemos o uso do useEffect para nos ajudar a focar no <input> assim que o usuário renderizasse o componente.

Usando o useMemo com Typescript

O useMemo é usado para memorizar o resultado de uma função de cálculo, de modo a evitar a reexecução desse cálculo a menos que suas dependências mudem.

Para mais informações sobre o funcionamento do useMemo no React, acesse este link.     

Para testarmos ele em conjunto com o Typescript, vamos criar um novo componente chamado de Calculadora.

Calculadora > index.tsx:

import React, { useMemo, useState } from 'react';

const Calculadora: React.FC = () => {
 const [número, setNúmero] = useState<number>(0);

 // Função de cálculo cara que só deve ser executada quando o número muda
 const cálculoCaro = (n: number) => {
 console.log('Calculando...');
 let resultado = 0;
 for (let i = 0; i < 1000000000; i++) {
 resultado += n * i;
 }
 return resultado;
 };

 // Usando useMemo para memorizar o resultado do cálculo
 const resultado = useMemo(() => cálculoCaro(número), [número]);

 return (
 <div>
 <p>Resultado do cálculo: {resultado}</p>
 <button onClick={() => setNúmero(prev => prev + 1)}>Incrementar Número</button>
 </div>
 );
};

export default Calculadora;

Note que a declaração do useMemo permanece com a mesma sintaxe daquela que vimos no ReactJS 😉

Usando o useContext com Typescript

O Context API (useContext) é um hook bastante utilizado, que nos permite transmitir dados entre componentes dentro da nossa aplicação feita com React.

Para mais informações sobre o funcionamento do useContext no React, acesse este link.

Vamos começar criando dentro da pasta contexts um novo contexto chamado de UserContext.tsx.

Contexts > UserContext.tsx:

// UserContext.tsx
import React, { createContext, useState, ReactNode, useContext } from 'react';

interface UserContextType {
 name: string;
 age: number;
 setName: (name: string) => void;
 setAge: (age: number) => void;
}

const UserContext = createContext<UserContextType | undefined>(undefined);

export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
 const [name, setName] = useState<string>('');
 const [age, setAge] = useState<number>(0);

 return (
 <UserContext.Provider value={{ name, age, setName, setAge }}>
 {children}
 </UserContext.Provider>
 );
};

export const useUser = () => {
 const context = useContext(UserContext);
 if (context === undefined) {
 throw new Error('useUser must be used within a UserProvider');
 }
 return context;
};

Note que no comando acima, estamos fazendo o uso das boas práticas da Interface, onde todos os estados existentes ali, foram declarados dentro da nossa interface chamada de UserContextType.

Note também que estamos tipando o createContext, que pode receber uma interface (UserContextType) quanto também algo indefinido (undefined), uma vez que o contexto é iniciado como indefinido ou vazio (null) antes de receber a interface propriamente dita.

Nós também precisamos tipar o createContext para que o nosso contexto consiga compreender os tipos de dados que ele estará trafegando.

Em seguida, vamos criar um novo componente chamado de UserComponent.

UserComponent > index.tsx:

// UserComponent.tsx
import React, { useState } from 'react';
import { useUser } from '../../contexts/UserContext';

const UserComponent: React.FC = () => {
 const { name, age, setName, setAge } = useUser();
 const [newName, setNewName] = useState('');
 const [newAge, setNewAge] = useState<number>(0);

 const handleUpdate = () => {
 setName(newName);
 setAge(newAge);
 };

 return (
 <div>
 <h1>User Information</h1>
 <p>Name: {name}</p>
 <p>Age: {age}</p>
 <input
 type="text"
 placeholder="Enter name"
 value={newName}
 onChange={(e) => setNewName(e.target.value)}
 />
 <input
 type="number"
 placeholder="Enter age"
 value={newAge}
 onChange={(e) => setNewAge(Number(e.target.value))}
 />
 <button onClick={handleUpdate}>Update</button>
 </div>
 );
};

export default UserComponent;

Observe que no comando acima, estamos fazendo o uso do nosso contexto que acabamos de criar, e o estamos recuperando por meio do useUser.

Por fim, não se esqueça de envolver a sua aplicação (App.tsx) para que todos os outros componentes (ou rotas) possam acessar o seu contexto:

import { UserProvider } from "./contexts/UserContext";
import UserComponent from "./components/UserComponent";

function App(){
 return(
 <UserProvider>
 <UserComponent />
 </UserProvider>
 );
}

export default App;

No caso do Context API, você pode observar um alto grau de tipagem do Typescript. Isso aconteceu pois o uso dos contextos envolvem a escrita de mais códigos, o que implica em mais tipagem.

Arquivos da lição

Os arquivos desta lição podem ser encontrados no repositório do GitHub por meio deste link.

Conclusão

Nesta lição, você aprendeu a utilizar todos os hooks mais importantes do React em conjunto com o Typescript.

Até a próxima lição!

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.