Context API e TypeScript: como utilizar o superpoder desta dupla
E aí, beleza?
Vamos bater um papo sobre um tema importante para a gente, pessoas que desenvolvem frontend com React: a combinação matadora da Context API com TypeScript. E claro, que tal embarcarmos nessa aventura com os nossos heróis preferidos, os Vingadores?
O que é essa tal de Context API?
Antes de sairmos voando com o Homem de Ferro ou lançando o escudo com o Capitão América, vamos colocar os pés no chão.
Quem já trabalhou com React sabe o quão trabalhoso pode ser passar dados entre componentes, especialmente em aplicações maiores. A Context API é uma solução nativa do React para esse desafio. Em vez de enviar informações através de múltiplos níveis de componentes, você cria um "contexto" que disponibiliza esses dados para qualquer componente que queira "escutá-los".
Existem outras formas de gerenciar dados, como Redux e MobX. Cada um tem suas vantagens, mas a Context API se destaca por ser integrada diretamente ao React, trazendo menos dependências e uma curva de aprendizado mais amigável.
E por que combinar com TypeScript?
Sabe o Thor com o martelo na mão? O TypeScript é isso. Ele nos dá poderes para entender e garantir que os tipos (as propriedades) dos nossos dados estejam corretos. Com ele, a gente evita bugs e garante que o Hulk não vai esmagar tudo por um erro bobo.
Agora, pensa só: Context API ajuda você a gerenciar os dados; TypeScript garante que o formato desses dados estão certos.
Beleza, mas e o código? Como fica?
Como utilizar Context API com Typescript?
Vem comigo para saber! Como exemplo, vou mostrar um código de um contexto que vai gerir qual é o membro dos vingadores que foi selecionado pela pessoa usuária:
Primeiro, em JavaScript:
import React, { createContext, useContext, useState } from 'react';
const VingadoresContext = createContext();
function VingadoresProvider({ children }) {
const [vingador, setVingador] = useState("Homem de Ferro");
return (
<VingadoresContext.Provider value={{ vingador, setVingador }}>
{children}
</VingadoresContext.Provider>
);
}
function useVingadores() {
return useContext(VingadoresContext);
}
E agora, o poder do TypeScript:
import React, { createContext, useContext, useState, ReactNode } from 'react';
interface VingadoresContextType {
vingador: string;
setVingador: React.Dispatch<React.SetStateAction<string>>;
}
const VingadoresContext = createContext<VingadoresContextType | undefined>(undefined);
interface VingadoresProviderProps {
children: ReactNode;
}
function VingadoresProvider({ children }: VingadoresProviderProps) {
const [vingador, setVingador] = useState<string>("Homem de Ferro");
return (
<VingadoresContext.Provider value={{ vingador, setVingador }}>
{children}
</VingadoresContext.Provider>
);
}
function useVingadores(): VingadoresContextType {
const context = useContext(VingadoresContext);
if (!context) {
throw new Error('useVingadores deve ser usado dentro de um VingadoresProvider');
}
return context;
}
Por que isso é tão espetacular?
Para começar, vamos decifrar essa linguagem técnica: React.Dispatch<React.SetStateAction
No React, frequentemente usamos o useState para gerenciar o estado local de nossos componentes. Por sua vez, a função setState (que você recebe de useState) pode aceitar um valor direto (para atualizar o estado) ou uma função que recebe o estado anterior e retorna o novo estado. Esse tipo complexo, React.Dispatch<React.SetStateAction
Em palavras mais simples, estamos dizendo: "Ei, TypeScript, essa é a função que vai atualizar o nosso estado, e ela pode aceitar diretamente uma string ou uma função que pega uma string e retorna outra string".
Já o ReactNode é uma forma elegante oferecida pelo React para tipar "qualquer coisa que pode ser renderizada":
- Componente;
- String;
- Número;
- Combinação deles.
Porém, nem sempre queremos ser tão genéricos. Às vezes, utilizamos tipos mais específicos como JSX.Element ou Element[] se soubermos exatamente o que esperar. No entanto, ReactNode nos dá flexibilidade.
Quando definimos o tipo <VingadoresContextType | undefined>, estamos considerando que o nosso contexto pode não ter sido inicializado. Isso é útil porque, no React, um contexto criado com React.createContext começa como undefined até que seja provido de um valor. Garantindo isso em nossa tipagem, evitamos erros potenciais.
Perceba as maravilhas: essa tipagem clara traz vantagens. Uma delas é que você captura erros em tempo de desenvolvimento, o que significa menos bugs na produção. O Intellisense do VSCode se torna ainda mais poderoso, sugerindo propriedades e métodos, e alertando você sobre possíveis problemas. Se você já usou React sem TypeScript, sabe como é fácil cometer pequenos erros e passar algum tempo debugando. Com TypeScript, muitos desses erros são evitados antes de rodar o código!
Conclusão
Espero que essa viagem pelo universo Marvel tenha esclarecido a combinação mágica da Context API com TypeScript.
Se está curtindo essas dicas e quer mais, se liga aqui na Alura. Tem muito conteúdo top sobre Frontend vindo por aí. Estuda com a gente? Aproveite para conferir os meus cursos sobre React. Vamos mergulhar juntos nesse mundo de possibilidades!
Até a próxima e... "Vingadores, avante!"