DEV Community

Cover image for Understand High Order Component Once and For All
Everaldo Junior
Everaldo Junior

Posted on

Understand High Order Component Once and For All

Intro

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 😉.

O que são High Order Components?

Assim como as High Order Functions o HOC é uma técnica que:

  1. Recebe um componente (função) como parâmetro e/ou retorna um novo componente
  2. É 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:

Caso problema

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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:

Gif com o funcionamento

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/>
}

...
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)