Artigo original: The React TypeScript Cheatsheet – How To Set Up Types on Hooks
O TypeScript permite a verificação de tipos em seu código, o que deixa o código mais robusto e compreensível.
Neste guia, mostrarei como definir os tipos do TypeScript em hooks do React (useState, useContext, useCallback e assim por diante).
- Definir tipos no useState
- Definir tipos no useRef
- Definir tipos no useContext
- Definir tipos no useReducer
- Definir tipos no useMemo
- Definir tipos no useCallback
Vamos começar.
Definir tipos no useState
O hook useState
permite gerenciar o state (em português, estado) em sua aplicação do React. É o equivalente a this.state
em um componente de classe.
import * as React from "react";
export const App: React.FC = () => {
const [counter, setCounter] = React.useState<number>(0)
return (
<div className="App">
<h1>Result: { counter }</h1>
<button onClick={() => setCounter(counter + 1)}>+</button>
<button onClick={() => setCounter(counter - 1)}>-</button>
</div>
);
}
Para definir tipos em um hook useState
, você precisa passar em <>
o tipo de state. Você pode usar um tipo com união (<number | null>
) se não tiver um state inicial.
Definir tipos no useRef
O hook useRef
retorna um objeto de referência mutável, que permite o acesso aos elementos do DOM.
import * as React from "react";
export const App: React.FC = () => {
const myRef = React.useRef<HTMLElement | null>(null)
return (
<main className="App" ref={myRef}>
<h1>My title</h1>
</main>
);
}
Como se pode ver, a forma como o useRef
recebe tipos é a mesma que a utilizada no hook useState
. É preciso apenas passá-los com <>
. Se você tiver diversas anotações de tipo, basta usar a união, como eu faço aqui.
Definir tipos no useContext
O useContext
é um hook que permite acessar e consumir um determinado contexto em uma aplicação do React.
import * as React from "react";
interface IArticle {
id: number
title: string
}
const ArticleContext = React.createContext<IArticle[] | []>([]);
const ArticleProvider: React.FC<React.ReactNode> = ({ children }) => {
const [articles, setArticles] = React.useState<IArticle[] | []>([
{ id: 1, title: "post 1" },
{ id: 2, title: "post 2" }
]);
return (
<ArticleContext.Provider value={{ articles }}>
{children}
</ArticleContext.Provider>
);
}
const ShowArticles: React.FC = () => {
const { articles } = React.useContext<IArticle[]>(ArticleContext);
return (
<div>
{articles.map((article: IArticle) => (
<p key={article.id}>{article.title}</p>
))}
</div>
);
};
export const App: React.FC = () => {
return (
<ArticleProvider>
<h1>My title</h1>
<ShowArticles />
</ArticleProvider>
);
}
Aqui, começamos criando a interface IArticle
, que é o tipo do nosso contexto.
Em seguida, a utilizamos no método createContext()
para criar um contexto. Depois, inicializamos o contexto com []
. Você também pode usar null
como o state inicial, se quiser.
Com isso feito, podemos, agora, lidar com o state do contexto e definir seu tipo em useContext
para que espere um array do tipo IArticle
como valor.
Definir tipos no useReducer
O hook useReducer
ajuda a gerenciar states mais complexos. É uma alternativa ao useState
– considere, no entanto, que eles são diferentes.
import * as React from "react";
enum ActionType {
INCREMENT_COUNTER = "INCREMENT_COUNTER",
DECREMENT_COUNTER = "DECREMENT_COUNTER"
}
interface IReducer {
type: ActionType;
count: number;
}
interface ICounter {
result: number;
}
const initialState: ICounter = {
result: 0
};
const countValue: number = 1;
const reducer: React.Reducer<ICounter, IReducer> = (state, action) => {
switch (action.type) {
case ActionType.INCREMENT_COUNTER:
return { result: state.result + action.count };
case ActionType.DECREMENT_COUNTER:
return { result: state.result - action.count };
default:
return state;
}
};
export default function App() {
const [state, dispatch] = React.useReducer<React.Reducer<ICounter, IReducer>>(
reducer,
initialState
);
return (
<div className="App">
<h1>Result: {state.result}</h1>
<button
onClick={() =>
dispatch({ type: ActionType.INCREMENT_COUNTER, count: countValue })
}> +
</button>
<button
onClick={() =>
dispatch({ type: ActionType.DECREMENT_COUNTER, count: countValue })
}> -
</button>
</div>
);
}
Aqui, começamos declarando os tipos de ação que permite lidar com o contador. Em seguida, definimos dois tipos para a função do redutor e para o state do contador, respectivamente.
O redutor espera um state
do tipo ICounter
e uma action
(em português, ação) do tipo IReducer
. Com isso, podemos, agora, lidar com o contador.
O hook useReducer
recebe a função do redutor e um state inicial como argumentos e retorna dois elementos: o state
do contador e a ação de dispatch
.
Para definir o tipo para os valores retornados por useReducer
, basta passar em <>
o tipo dos seus dados.
Com isso, o contador, agora, pode ser aumentado e reduzido usando o useReducer
.
Definir tipos no useMemo
O hook useMemo
permite a memoização do resultado de determinada função. Ele retorna um valor memoizado.
const memoizedValue = React.useMemo<string>(() => {
computeExpensiveValue(a, b)
}, [a, b])
Para definir os tipos em useMemo
, basta passar em <>
o tipo dos dados que você deseja memoizar. Aqui, o hook expera por uma string
como valor retornado.
Definir tipos no useCallback
O hook useCallback
permite que você faça a memoização de uma função para evitar novas renderizações desnecessárias. Ele retorna uma função de callback memoizada.
type CallbackType = (...args: string[]) => void
const memoizedCallback = React.useCallback<CallbackType>(() => {
doSomething(a, b);
}, [a, b]);
Aqui, declaramos o tipo de CallbackType
usado como tipo na função de callback que queremos memoizar.
Ela espera receber parâmetros do tipo string
e deve retornar um valor do tipo void
.
Em seguida, definimos esse tipo em useCallback
– caso você passe o tipo incorreto para a função de callback ou para o array de dependências, o TypeScript dirá que há algo errado.
Você pode encontrar mais conteúdo como este no blog do autor ou seguir o autor no Twitter para receber notificações.
Obrigado pela leitura.