O que é o Context API?

No React, quando precisamos que um componente filho tenha os dados do pai, precisamos informar esses dados e funções através das props no componente filho, como pode ser visto na Figura 1.

Componente filho recebendo props do componente
pai
Figura 1. Componente filho recebendo props do componente pai

Com a chegada do Context API no React (a partir da versão 16) esse cenário é diferente, ao invés de passar esses dados através de props, criamos um context que armazena esses dados. Dessa forma, os componentes que precisam dessa informação podem consumi-las. Esse processo possui o mesmo princípio do Redux, sendo que o Context API é nativo no próprio React. Caso você já possua conhecimento prévio em Redux, será mais fácil entender e como usar o Context API, por conta que eles possuem a mesma filosofia, gerenciamento de estados.

Porque o Context é útil?

O conceito de estado ficou complexo à medida que foi necessário compartilhar o estado dentro da aplicação de uma forma global entre os componentes. Para isso, algumas bibliotecas surgiram para resolver essa nova demanda, como o Redux e MobEx. O Redux é a biblioteca mais utilizada para gerenciamento de estados.

O React context API é um gerenciador de estado global e é uma funcionalidade implementada a pouco tempo no ecossistema do React, podendo resolver 90% das soluções do Redux de forma extremamente simples.

Na Figura 2 temos uma representação mais ilustrativa da diferença do uso de props e de Context API.

Diferença do uso de props e context API
Figura 2. Diferença do uso de props e context API

Note que sem a utilização do context, os dados serão repassados através da árvore de componentes (componente através do outro). Já usando o context, esses mesmos dados já estarão disponíveis e compartilhados por todos os componentes que precisarem dessa informação.

Aplicando context

Neste ponto criaremos um exemplo de contador que incrementará um valor ao ser clicado utilizando o Context API.

Primeiramente vamos criar um arquivo que gerenciará o nosso contexto, chamado Context.js. Veja o seu código no Código 1.

  import React, { createContext } from 'react';
   
  const Context = createContext(0);
   
  export default Context;
Código 1. Código do arquivo Context.js

Explicando o código.

Linha 1: Importamos o React, e junto com ele colocaremos em chaves a função de createContext.

Linha 3: Vamos criar um contexto chamado Context. Para isso utilizamos a função createContext que recebe 0 como valor inicial. Feito isso, o contexto foi criado.

Linha 5: Exportamos o nosso Context para ser utilizado por todos os componentes que importá-lo.

Agora importaremos nosso contexto criado no arquivo App.js (Código 2) para que dentro dele seja inserido os componentes que poderão compartilhar os dados salvos no contexto.


  import React from 'react';
  import Context from './Context';
   
  export default function App() {
    return (
      <Context.Provider>
        <div>
          <p> DevMedia Context API</p>
        </div>
      </Context.Provider>
    );
  }
Código 2. Arquivo App.js importando o contexto Context

Explicando o código:

Linha 1: Importamos o React.

Linha 2: Importamos o contexto criado em context.js, pra usá-lo no nosso arquivo App.js

Linha 4: Criamos um componente funcional declarado como App, com o mesmo nome do nosso arquivo, e o exportamos na mesma linha.

Linha 6: Usaremos a constante Context da mesma forma que um componente, ou seja, com tag de abertura e fechamento. Repare que aqui utilizamos Context.Provider para que dentro dele possamos inserir os componentes que podem utilizar este contexto. Com isso, todos os componentes dentro de Context.Provider poderão utilizar o contexto Context.

Agora criaremos o componente de Counter, que vai exibir o botão que altera o valor da variável total que será armazenada no contexto, conforme o Código 3.

  import React, { useContext } from "react";
   
  import Context from "./Context";
   
  export default function Counter() {
    const [total, setTotal] = useContext(Context);
   
    return (
      <div>
        <h3>{total}</h3>
        <button type="button" onClick={() => setTotal(total + 1)}>
          Contador
        </button>
      </div>
    );
  }
Código 3. Criando o componente Counter

Explicando o código:

Linha 1: Usaremos o hook useContext para conseguirmos usar o contexto.

Linha 3: Com o useContext proporcionaremos o nosso contexto dentro do nosso componente que queremos utilizar. Essa função retorna ao componente o valor do contexto atual. Lembrando que para acessar esse valor o componente precisa estar inserido no provider do contexto (componente Context.Provider inserido no componente do arquivo App.js).

Linha 5: Declaramos e exportamos o componente funcional de Counter.

Linha 6: Usando o useContext receberemos os dados do contexto Context. O valor total atual do contador e o setTotal é a função que será usada para atualizar total a cada clique do usuário. Esse código é similar a criação de uma variável de estado utilizando useState, isso porque nosso contexto vai armazenar uma variável de estado.

Linha 10: Imprime o valor atual (valor armazenado no contexto) usando a expressão do JSX, entre as chaves.

Linha 11: Criamos um botão do tipo button, e na sua propriedade onClick uma função anônima que a cada clique receberá o valor atual do total incrementado de 1.

Neste momento temos a estrutura básica para entender o conceito de Context API. Neste momento ainda não funcionará do jeito que queremos, ou seja, exibindo o valor do contador e o botão para incrementar um a cada clique. Veja a aparência atual do projeto na Figura 3.

Aparência atual do projeto
Figura 3. Aparência atual do projeto

Para que a aplicação exiba o botão que vai utilizar o contexto, precisamos fazer algumas alterações no nosso projeto.

Primeiramente modificaremos o arquivo App.js para implementar o hook useState. É através dele que vamos criar a variável que armazenará o valor que será exibido e incrementado pelo botão.

Veja no Código 4 o componente App atualizado.

  import React, { useState } from 'react';
  import Context from './Context';
  import Counter from './Counter';
   
  export default function App() {
    const [total, setTotal] = useState(0);
   
    return (
      <Context.Provider value={[total, setTotal]}>
        <div>
          <p>App.js: { total }</p>
          <p> DevMedia Context API</p>
          <Counter />
        </div>
      </Context.Provider>
    );
  }
Código 4. Componente App criando a variável de estado

Entenda o que alteramos:

Linha 1: Neste ponto além do React importamos também, o useState.

Linha 3: Importamos o componente de Counter.js que exibe o botão que incrementará a variável total.

Linha 6: Usamos o useState para criar uma variável de estado que terá um valor inicial de 0. Lembrando que total é a variável de estado e setTotal é a função que vai alterar o seu valor.

Linha 9: No Context.Provider passamos um parâmetro chamado value que armazenará a variável de estado que criamos utilizando o useState. A ordem inserida (variável e função) é importante para termos a consistência dos dados que serão transmitidos dentro do contexto. A partir deste momento, já é possível usar o contexto sempre que houver necessidade. Lembrando que os componentes devem estar dentro do meu Provider.

Linha 11: Imprimimos o valor total em nosso componente App.js.

Linha 13: Invocaremos o nosso componente Counter.js.

O componente Couter só consegue utilizar o contexto Context porque ele está inserido dentro de Context.Provider.

Para deixarmos nosso contexto padronizado com o valor que ele receberá, vamos atualizar o arquivo Context.js como exibido no Código 5.

  import React, { createContext } from 'react';
   
  const Context = createContext([0, () => {}]);
   
  export default Context;
  
Código 5. Arquivo Context padronizado com o valor que ele vai receber em App.js

Repare que a alteração feita está padronizada com o código usado para criar a variável de estado através de useState, ou seja, uma variável e uma função.

Agora podemos acessar o terminal onde está o projeto e executá-lo usando o Código 6.

npm start
Código 6. Comando usado para executar a aplicação

Repare na Animação 1 que a cada clique no botão contador, o valor total será incrementado.

Projeto criado utilizando o contexto
Animação 1. Projeto criado utilizando o contexto

Veja no flow abaixo o resumo do projeto criado:

flow flow flow flow flow flow flow flow flow

Conclusão

O Context é uma ferramenta poderosa dentro do React. Ela é usada para gerenciar os estados dos seus componentes dentro de uma aplicação web sem precisar usar algum pacote para isso. Espero que tenham gostado e até a próxima.