Meu primeiro Higher-Order Component

Muitos ouvem falar e muitos me perguntam sobre. Para aqueles que são iniciantes neste universo do React este ainda é um grande mistério. Através deste tutorial pretendo introduzi-los neste interessante padrão de composição.

Rafael Maruta
React Brasil
Published in
7 min readJun 12, 2018

--

Imagem emprestada de https://medium.com/@Farzad_YZ/handle-loadings-in-react-by-using-higher-order-components-2ee8de9c3deb

Olá galera, como vocês estão? =D

Após um bom tempo sem escrever por dedicação a outros projetos, estou de volta nesta série que visa guiar os iniciantes pelo Ecossistema do React. Se este é o primeiro artigo que você está vendo, recomendo que depois você dê uma olhada nos meus outros artigos, acredito que você encontrará boas dicas sobre React! Segue o link abaixo:

Há algumas formas de se fazer abstração no React. Há os antigos Mixins que foram descontinuados na versão 0.13. Hoje vou falar sobre Higher-Order Components.

O que são Higher-Order Components?

Higher-Order Component (HOC), como definiu o Dan Abramov (co-autor do Redux) é apenas uma função que pega um componente existente e retorna um outro componente, envolvendo-o (wrapper) atribuindo-lhe novas funcionalidades. Ele se originou das Higher-Order Functions, que é um outro padrão de desenvolvimento. É interessante para isolar lógicas de componentes em uma função caso você queira reaproveitá-las em outros componentes, ou apenas para separar a lógica mesmo, ou simplesmente isolar em outro lugar para deixar o componente puro. Abstraímos comportamentos do React como lifecycles, requisições às APIs feitas nestes lifecycles, PropTypes, defaultProps etc. Vamos seguir para o tutorial.

Implementando meu primeiro Higher-Order-Component

Seguiremos abaixo com o tutorial de criar um HOC. Vamos criar um simples HOC que mostra um loading em vários componentes até ele haver uma mudança de estado e ele receber uma prop dizendo que ele está ok, e assim exibir o conteúdo. Vamos aproveitar o logo giratório do React que está contido no Create React App (explicação sobre o que é isto logo abaixo) para usá-lo como loading.

1. Instale e rode o Create React App

Create React App é um boilerplate criado pelo Facebook para iniciar rapidamente um projeto com React. Ele já vem com algumas dependências e plugins instalados, além de algumas pré-configurações.

Caso você possua npm 5.2+ ou maior, poderá instalar desta forma:

npx create-react-app create-react-hoc-app

Se não tiver, é necessário instalar o Create React App globalmente. Rode em seu terminal o comando:

npm i -g create-react-app

… e ao finalizar:

create-react-app create-react-hoc-app

O create-react-hoc-app é o nome da pasta que será criada. Agora entre na pasta:

cd create-react-hoc-app

… e rode com Yarn:

yarn start

ou com npm:

npm start

Uma janela no navegador abrirá, na porta http://localhost:3000/ exibindo:

2. Limpe a View para o tutorial

Acesse o arquivo create-react-hoc-app/src/App.js e deixe a marcação da seguinte forma:

Isto exibirá um simples texto Teste em http://localhost:3000.

3. Crie os 3 componentes que serão exibidos

Crie uma pasta ./src/components e nela crie 3 arquivos: Infos.js, ReposList.js e StarredList.js. Nossa ideia inicial é exibir cada um destes 3 componentes assíncronamente após o loading, com diferentes tempos cada um.

Em cada componente, insira o conteúdo correspondente:

./src/components/Infos.js:

./src/components/ReposList.js:

./src/components/StarredList.js

Note que são marcações de componente simples, mas que iremos reaproveitar no próximo artigo para fazer integração com a GitHub API. Lembrando que como o foco são os componentes, acabei abrindo mão de usar alguma lib de estilos para usar style inline mesmo. Os dados que estão chumbados você pode substituir pelo seu próprio conteúdo.

4. Edite o arquivo ./App.js para exibir os componentes

Agora devemos inserir neste arquivo os componentes que acabamos de criar. Ele deverá ficar desta forma:

Acessando o http://localhost:3000/, você deverá visualizar algo parecido com isto:

Simplão apenas para captarmos a ideia

5. Prepare os componentes criados para receberem o Higher-Order Component

Em cada um dos componentes que estão na pasta ./src/components precisaremos fazer apenas duas alterações: uma é importar o HOC e a outra é envolver o nosso componente com ele. As alterações estão na segunda e na última linha de cada componente:

./src/components/Infos.js
./src/components/ReposList.js
./src/components/StarredList.js

É desta forma, na última linha de cada componente, que envolvemos o nosso componente com novas funcionalidades, passando ele como parâmetro para o nosso HOC, que retornará um novo componente.

6. Crie o Higher-Order Component

A ideia deste HOC é que enquanto não houverem dados chegando, for false, ou falsy, ele exiba o loading.

Crie uma pasta ./src/hocs e nela um arquivo chamado withLoading.js com o seguinte conteúdo:

Agora explicarei linha por linha o que está acontecendo:

  • Linha 1: importação da biblioteca do React.
  • Linha 2: importação da biblioteca de PropTypes, lembrando que ela foi movida para um pacote separado do React a partir da v15.5.
  • Linha 3: importação do logo do React que já estava sendo usado pelo Create React App. Como ele gira muito devagar, você pode acessar o arquivo ./src/App.css, na classe .App-logo, na propriedade animation e reduzir o tempo de rotação de 20s para aproximadamente 1s.
  • Linha 5: criação da nossa função que recebe o componente como argumento. Lembre-se que em cada componente que criamos, passamos ele próprio como parâmetro para esta função withLoading.
  • Linha 6: função que cria um novo componente e que recebe as props como argumento (no caso usei destructuring arguments para trazer apenas a propriedade que iremos usar, o data).
  • Linha 7: faz um if ternário que checa se a prop data está definida, é igual a true ou truthy.
  • Linha 8: caso a linha 7 resulte em true, cairá nesta linha, que exibe o nosso componente repassando a prop data para ele.
  • Linha 9: caso a linha 7 resulte em false, exibirá a imagem do logo do React girando.
  • Das linhas 10 à 13: atributos do elemento <img />.
  • Das linhas 16 à 18: definição da PropType da prop data.
  • Linha 20: retorno do componente recriado.

Em contextos gerais, você compreendeu o que acontece aqui? Basicamente criamos uma nova função onde o corpo dela constrói um novo componente em React e o retorna, e que inclusive definimos suas PropTypes (linha 16 à 18). Este novo componente poderia até ser um componente baseado em classe, com seus próprios lifecycles, que inclusive usaremos em nosso futuro exemplo de HOC que faz fetch de APIs.

Agora no http://localhost:3000 estará aparecendo somente os ícones do React girando:

7. Modifique o ./App.js para que ele exiba cada um dos componentes após um tempo

Por enquanto vamos usar um simples setTimeout para exibir cada um dos componentes com conteúdo após um determinado tempo de loading apenas para entendermos o funcionamento da HOC. Vamos aproveitar a função evolução de estado do React setState para isto. Isto poderia muito bem ser feito após a requisição à uma API, mas como dito, deixaremos isto para a próxima parte do artigo. Nosso HOC poderia muito bem ser aproveitado neste caso.

Nosso novo ./src/App.js ficará assim:

A seguir comentarei as alterações:

  • Das linhas 9 à 13: definição do initial state de cada estado que iremos posteriormente evoluir. Cada estado pertencerá a cada um dos 3 componentes que criamos.
  • Das linhas 15 à 19: chamada do lifecycle do React componentDidMount, onde é realizada a evolução de cada um dos estados inicialmente definidos nas linhas 9 à 13. Cada um dos estados é evoluído em momentos diferentes para ficar clara distinção entre eles na UI.
  • Das linhas 22 à 26: é feito destructuring object para que cada propriedade útil do objeto this.state, que contém o estado da aplicação, possa ser chamadas como variável.
  • Das linhas 30 à 32: são passadas props com os respectivos estados para os nossos 3 componentes.

Assim você notará cada um dos 3 componentes aparecendo após o loading em tempos distintos:

Após 1 segundo
Após 1 segundo e meio
Após 2 segundos

Com isto, finalizamos o nosso tutorial. Como ele já ficou meio longo, realmente postarei o tutorial com o HOC + fetch API no próximo post, que será a parte II. Segue abaixo o link do repositório do Git deste tutorial:

Conclusão

É interessante citar que a função connect do React Redux que conecta o React ao Redux é um HOC. Confira em meu tutorial sobre Redux:

Para auxiliar na implementação de HOCs temos os decorators, onde a ideia é basicamente fazer o que as HOCs e HOFs já fazem, decorar componentes ou funções. Com decorators fica mais fácil usar simultaneamente múltiplos HOCs e ainda passar mais parâmetros para eles. Esta feature no momento está no estágio 2 de aprovação, porém é possível já usá-la através de plugin do Babel. Caso tenha curiosidade eu recomendo-lhe que dê uma pesquisada sobre.

As HOCs se beneficiam muito de outro recurso de composição, chamado Render Props, recomendo que você dê uma olhadinha também.

Uma lib que complementa a utilização de HOCs é o Recompose. Como eles mesmos dizem, é como se fosse um Lodash para o React.

Recomendo também que você dê uma lida neste artigo que explica muito didaticamente a implementação de uma HOC, deixando clara a sua utilidade:

Documentação oficial:

Espero ter lhe ajudado ou acrescentado algo. Caso queira reforçar ou recomendar algo, ou obter esclarecimento sobre algo, é só postar um comentário!

Obrigado e Abraços!

--

--