Utilizando Context no React

Utilizando Context no React

Quando estamos falando de uma aplicação React comum, geralmente os dados são passados por hierarquia (de um componente “pai” para “filho” por meio de estados, ou de um componente “filho” para “pai” por meio de funções). Entretanto, esta forma de compartilhamento de informações fica muito complicada e extensa quando há muitos componentes envolvidos ou muitos níveis de hierarquia.

É visando solucionar esta questão que trazemos neste artigo uma forma de compartilhar dados globais sem nenhuma complexidade no código utilizado, por meio de uma funcionalidade do React chamada Context. Vamos lá?

Por que utilizar o Context?

Antes de começar a explicar como utilizar o Context, é necessário destacar a sua importância e o quanto ele pode nos ajudar. Para isto, vamos abordar o exemplo de uma aplicação em que faça sentido o seu uso: imagine conosco a seguinte hierarquia dentro de um determinado projeto:

Figura 1: Esquema do projeto Context-Project.


Na aplicação Context-Project, temos um componente App que possui dois outros que chamamos de Form e Presentation. O Form é o responsável por coletar dados do usuário, enquanto o Presentation possui a função de exibir estes dados, por meio do componente Data que é implementado nele.

Se fôssemos utilizar estados e props para repassar os dados preenchidos de Form e apresentá-los em Data, seria necessário criar estados em App que seriam passados via props para Presentation. Este por sua vez passaria os dados para o componente Data também via props (a coisa já começa a ficar repetitiva, não é?).

Além disso, visto que Form é o responsável pela coleta dos dados, os estados de App precisam ser atualizados por ele, o que gera a necessidade de repassar para Form via props funções que alteram estes estados. Muito extenso, não acha? E se a gente dissesse que é possível enviar estes dados para um determinado lugar por meio do componente Form de forma que Data poderá acessá-los diretamente? Isso mesmo, estamos falando do Context.

Com o Context é possível criar um arquivo que armazenará todos os dados e métodos de alteração dos mesmos, de forma que qualquer componente previamente permitido possa acessar e utilizar as informações salvas.

Primeiros passos

Utilizaremos o esquema da figura 1 para criar um projeto que utiliza o Context. Sendo assim, vamos começar criando o projeto por meio do nosso terminal com os seguintes comandos abaixo (se tudo der certo, uma página será carregada em seu browser com a logo do React):

npx create-react-app context-project

cd context-project

npm install

npm start

💡
OBS - Foi utilizado o npm como ferramenta de gerenciamento de pacotes, mas sinta-se à vontade para utilizar a que lhe for mais confortável.

Agora é hora de criar o componente Form que enviará os dados para Presentation e Data. Ele possuirá alguns inputs dos tipos texto, data e número, onde poderão ser preenchidos os dados de nome de um projeto, data da conclusão, número de pessoas envolvidas e link de uma imagem. Todas estas informações preenchidas serão salvas em estados locais pertencentes ao Form:

Figura 2: Componente Form.

É possível perceber que os valores salvos nos estados ainda não foram utilizados para nada, mas resolveremos isto nos próximos passos por meio da criação do Context.

Estruturando o Context

A primeira ação a ser feita é criar o arquivo onde iremos guardar as informações referentes às variáveis globais que todos os componentes terão acesso. Esta ação é feita pela função createContext, que importaremos da biblioteca react. O createContext será armazenado em uma constante e exportado para que possamos utilizá-lo no restante da aplicação:

Figura 3: Criação do context.


Uma vez feito o local de armazenamento de nossas variáveis globais, precisamos agora criar uma função que será responsável por manipular as informações salvas no Context e provê-las para o restante do código. Para isso realizaremos cinco passos:

  • Importar o arquivo context que acabamos de criar (o nome context será substituído pelo que você deu ao arquivo context onde se encontra a função createContext);
  • Inserir a propriedade children na função, que permite acesso a todos os “filhos” de um determinado componente;
  • Criar um componente context.Provider que será responsável por prover os dados do context para o resto da aplicação;
  • Adicionar uma propriedade a este componente context.Provider chamada value, que receberá como valor os dados que estarão disponíveis para o projeto (a propriedade value é obrigatória e sem ela a nossa implementação não funcionará);
  • Inserir dentro do componente context.Provider o elemento children que nós trouxemos via props.
Figura 4: Criação da função que irá manipular o context e provê-lo para o projeto.

Feito isto, criamos a estrutura básica do nosso context. Ele ainda se encontra sem nenhuma informação a ser compartilhada (por isso as aspas como valor de value), mas está pronto para tal. É isto que fazemos agora.

Manipulando o Context

Como já foi dito, a função ProjProvider é responsável por criar, manipular e conceder dados para o context. Vamos expandir estes três conceitos detalhadamente para que nada seja passado despercebido e você domine completamente esta funcionalidade.

No projeto que estamos utilizando como exemplo existem quatro dados importantes: o nome do projeto, a data de conclusão, o número de participantes e o link da imagem. Estas informações já estão salvas no estado do componente Form, mas só ele possui acesso a elas. Para que todos os componentes possam obter estes dados por meio do context precisamos criá-los também em ProjProvider.

Você pode se perguntar o porquê então de existirem estes estados no componente Form se os mesmos também serão criados em ProjProvider, mas aqui fica uma importante sugestão: para este caso e casos semelhantes, é muito mais rentável enviar para o context todas as informações de uma vez (via onClick) do que a cada mudança dentro de um dos inputs (via onChange). Esta última maneira geraria uma série de renderizações que seriam desnecessárias para a aplicação.

Figura 5: Criação dos estados globais do context.


Uma vez criados os estados que armazenam as informações, precisamos agora manipulá-los. Qualquer função que tenha este objetivo também deve ser criada em ProjProvider.

Queremos que, ao clicar no botão “Adicionar“ existente em Form, todos os valores dos estados locais deste componente sejam enviados para o estado global localizado em ProjProvider. Para isto, criaremos uma função update que receberá como parâmetro os quatro estados locais de Form e os guardará nos estados globais.

Figura 6: Criação da função de manipulação dos estados globais.

Precisamos também conceder aos demais componentes a possibilidade de acessarem tanto a função que criamos quanto os estados globais, de acordo com cada necessidade da implantação. Podemos para este objetivo criar uma constante que armazene tudo o que deve ser compartilhado e repassar esta constante como valor da propriedade value do context.Provider, conforme mostra a figura seguinte:

Figura 7: Tornando os dados do context acessíveis para os demais componentes.


O próximo passo é encapsular toda a parte da nossa aplicação que pode ter acesso ao que está criado, manipulado e concedido pelo componente ProjProvider (é para isto que estamos utilizando o children, para que tudo o que estiver dentro do componente tenha acesso ao context). Faremos isto no componente principal App.

Figura 8: Encapsulando o código com o componente ProjProvider.

Uma vez que criamos os estados necessários e construímos os métodos para manipulação e concessão deles, precisamos acessar estas funções com os componentes Form e Data. É aqui que entra em ação o hook useContext.

Utilizando o useContext

No componente Form realizaremos duas novas importações: o hook useContext da biblioteca react e o arquivo context do local de onde o criamos. Depois criaremos uma constante que receberá a chamada deste hook, onde será passado o context como parâmetro dela. Por fim, extraímos de dentro desta constante criada o que está no context que é necessário para a implementação (neste caso, apenas a função update). A função update será utilizada no evento de clique do botão, onde passaremos os quatro estados locais como parâmetro.

Figura 9: Método de acesso à função update por meio do componente Form.

Tudo certo! Agora já estamos atualizando o context por meio dos inputs criados no componente Form. Resta então acessarmos os estados globais para exibir por meio do componente Data estas informações. A forma como fazemos não é muito diferente do que já foi visto até aqui: precisaremos realizar as mesmas importações, com a diferença de que o que será trazido do context não será a função update e sim os quatro estados globais criados em ProjProvider:

Figura 10: Componente Presentation.

Figura 11: Componente Data.

Figura 12: Código em execução.

Simples, não acha? Após estes passos, nosso projeto está funcionando da maneira como planejamos!


Considerações Finais

O Context é uma ferramenta incrivelmente simples de se utilizar quando o assunto é gerenciamento de dados. Todavia, algumas precauções devem ser tomadas. Você vai perceber que, quanto maior a sua aplicação, mais e mais estados e funções são criados no Provider (ProjProvider), tornando o componente longo e até mesmo complicado de se referenciar ou encontrar algo.

Desta forma, se o projeto que você irá criar ou está criando é robusto ou está começando a ficar, é interessante e recomendado utilizar mais de um context (não muda muita coisa e só é preciso repetir o mesmo processo apresentado nas figuras 3, 7 e 8), de forma que cada arquivo seja responsável por uma determinada área da implementação.

Bons estudos e boa implementação!

💡
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.