Você ja ouviu falar nos High Order Components?
Introdução
Fala galera, tudo beleza? Hoje vou explicar um conceito considerado um tópico intermediario/avançado e bastante utilizado por algumas libs no React e React Native, os chamados High Order Components, nesse post vou te mostrar qual problema eles resolvem e como implementa-los 😉.
Obs: no fim desse post tem um link para um vídeo onde eu explico os mesmo conceitos!
O que são High Order Components?
Assim como as High Order Functions o HOC é uma técnica que:
- Recebe um componente (função) como parâmetro e/ou retorna um novo componente
- É util para se reutilizar a lógica de um componente, reforçando o DRY (Don't Repeat Yourself no seu código)
Caso Problema
Imaginemos o seguinte caso: um aplicação simples que tem dois componentes que são "populados" através de uma API - O nome e cargo do usuário, dessa forma:
A lógica dentro de cada componente é a seguinte:
NameBox.tsx
import * as React from 'react';
interface NameBoxProps {
data: string | null;
}
function NameBox({ data }: NameBoxProps) {
if (!data) {
<div style={{ backgroundColor: 'gray', width: 120, height: 120 }}>
<p>Carregando...</p>
</div>;
}
return (
<div style={{ backgroundColor: 'green', width: 120, height: 120 }}>
<p>{data}</p>
</div>
);
}
export default NameBox;
JobBox.tsx
import * as React from 'react';
interface JobBoxProps {
data: string | null;
}
function JobBox({ data }: JobBoxProps) {
if (!data) {
<div style={{ backgroundColor: 'gray', width: 120, height: 120 }}>
<p>Carregando...</p>
</div>;
}
return (
<div style={{ backgroundColor: 'orange', width: 120, height: 120 }}>
<p>{data}</p>
</div>
);
}
export default JobBox;
Basicamente é um componente que recebe uma propriedade chamada data
e a exibe dentro de uma tag div, se data não tiver um valor verdadeiro, o componente exibe a frase 'Carregando'.
Como no exemplo abaixo:
Bom, o que temos de problema aqui?
Estamos utilizando a mesmissima lógica para exibir o status de "Carregando..." em dois lugares diferentes.
E agora você pode pensar:
Que tal, criarmos um componente de e chama-lo nos dois componentes?
Seu pensamento está correto, criando um novo componente de loading conseguimos abstrair um pouco mais nosso código, deixando ele mais reutilizavél e com uma manutenção um pouco mais fácil, porém a lógica a seguir ainda seria repetida nos dois componentes:
...
if (!data) {
<Loading/>
}
...
Bom, e como conseguimos resolver isso de uma maneira super elegante? Exatamente, com High Order Components!
Criando um High Order Component
Como eu disse lá no começo, um HOC é um componente que recebe um componente como parâmetro e retorna um novo componente, e é examente isso que vamos fazer:
Primeiro criamos um arquivo chamado withLoader.tsx
e dentro dele vamos criar um componente que recebe um componente como parâmetro e retorna outro componente (é bastante componente eu sei...) desta forma:
import * as React from 'react';
const withLoader = (Component: React.ElementType) => (props: any) => {
return <Component {...props} />
};
export default withLoader;
Desta forma temos acesso ao componente e as props que ele tem.
A última coisa que temos que fazer por aqui é verificarmos se nossa propriedade data
existe , se existir retornamos o Componente que está sendo passado como parâmetro, se não retornamos nossa div com o "Carregando..."
Ficando dessa fora:
import * as React from 'react';
const withLoader = (Component: React.ElementType) => (props: any) => {
return !props.data ? (
<div style={{ backgroundColor: 'gray', width: 120, height: 120 }}>
<p>Carregando...</p>
</div>
) : (
<Component {...props} />
);
};
export default withLoader;
Pronto, agora nossa lógica de exibição e componente de carregamento estão em um lugar só, mas como fazer com que os componentes JobBox.tsx e NameBox.tsx se utilizem disso?
Basta chamar o withLoader passando nosso componente como função:
import * as React from 'react';
interface NameBoxProps {
data: string | null;
}
function NameBox({ data }: NameBoxProps) {
return (
<div style={{ backgroundColor: 'green', width: 120, height: 120 }}>
<p>{data}</p>
</div>
);
}
// Passamos o NameBox como parâmetro do nosso HOC withLoader
export default withLoader(NameBox);
E pronto, agora temos um High Order Component em uso! Deixando nosso código bem mais modularizado, melhorando a reutilização e manutenção do nosso código.
Libs que utilizam High Order Components
Segue algumas libs que usam HOCs e que você talvez não tenha percebido, ou não sabia do que se tratava
- Redux (React)
- Apollo (React)
- Code Push (React Native)
- React Navigation (React Native)
Conclusão
Vimos que High Order Components são excelentes para respeitarmos o DRY e modularizarmos nosso código, que sua implementação nem é tão complicada assim como o nome faz parecer e que eles são excelentes para resolvermos alguns problemas do dia-a-dia.
Se você quiser ver esse mesmo conteúdo em formato de vídeo, entre nesse link, tenho feito videos de vários padrões de JS e React focados no front-end!
Até a próxima!
Link do projeto no StackBlitz: https://react-ts-9f1nvy.stackblitz.io
Canal no Youtube: Everaldev - YouTube