Compartilhando comportamento no React

Dimas Cyriaco
Sep 4, 2018 · 4 min read

Reutilização de código é um dos principais pilares do desenvolvimento de software. É o conceito por trás de ideias básicas como funções, orientação a objetos e muitas outras.

No mundo do React, inicialmente, a forma idiomática de compartilhar comportamento entre componentes era através de mixins.

Suponha o seguinte componente que simplesmente conta o número de vezes que o usuário clica em um botão.

Agora, digamos que você queira utilizar a mesma lógica em outro componente. Contar quantas vezes o usuário faz hover em uma imagem, por exemplo.

Voce teria que adicionar o state count e repetir a função que incrementa o contador nesse novo HoverCounter.

Mixins

Para evitar essa repetição, o time do React criou os mixins. Com eles, era possível extrair esse comportamento comum e reutilizá-lo.

Essa técnica resolvia a questão do compartilhamento de código, mas tinha vários problemas.

O mais óbvio (e de certa forma mais urgente), era o fato de que os mixins eram incompatíveis com a nova sintaxe de classes que foi introduzida no ES6, e que vinha se popularizando na época.

Mas haviam outros problemas mais sutis, como a possibilidade de colisão de nomes: imagine que o App do exemplo acima adicione outro mixin que tenha um state chamado count. Isso poderia causar problemas difíceis de debugar.

Porém, para mim, o pior problema era o da indireção. Não fica claro, para quem olha para o componente App, da onde esta vindo this.state.count e this.handleClick. São valores mágicos que simplesmente aparecem no seu componente.

Lembre-se de que o código do mixin podia estar em outra parte do code base, ou, até mesmo, ser uma dependência externa. Para piorar, um componente podia ter diversos mixins. Para saber o que vinha cada um desses valores mágicos ficava complicado.

Numa tentativa de resolver, principalmente, o problema da incompatibilidade com a sintaxe de classes, a comunidade React concebeu o famigerado…

Higher Order Component

Ou ‘Componente de alta ordem’.

A ideia dessa técnica é extrair a lógica a ser compartilhada para um outro componente que usa o seu componente internamente.

No nosso exemplo do contador, o primeiro passo seria mudar nosso App para receber o que vinha do mixin, como uma prop.

A lógica do contador em si fica em outro componente:

A idéia básica é essa.

No código acima a gente ‘marretou’ o App no render do Counter para ficar mais fácil de entender, mas, obviamente a gente não conseguiria reutilizar o Counter desse jeito. A gente tem que achar uma forma do Counter receber o App como 'parâmetro'.

E esse é o pulo do gato dos ‘HOC’. Criar uma função que recebe o seu componente como parâmetro (no caso, o App) e retorna uma versão do Counter que utiliza esse parâmetro no render. Dessa forma a gente pode passar outros componentes para essa função, e usar a lógica do contador em vários lugares. Parece complicado, né? Olhando o código fica mais fácil de entender.

Como voce pode ver, essa função cria e retorna um novo componente. Esse novo componente vai renderizar o componente que foi passado como parâmetro.

Para gerar uma versão do seu componente com o contador:

Pronto, agora o App tem um contador, e qualquer outro componente também pode ter.

Esse técnica resolve alguns dos problemas que a gente tinha com os mixins, o principal deles é que ela funciona com classes.

Porem, ele introduz alguns outros problemas, como encadeação de HOCs. Imagina que a gente queira usar um outro HOC, que adiciona a prop xpto no nosso componente, por exemplo. Se a gente fizer:

O componente AppWithCounterAndXPTO não teria a prop xpto, porque no render do nosso HOC a gente não passa essa prop para o App.

A gente teria que mudar o render do nosso HOC para retornar:

Dessa forma a gente passaria adiante qualquer prop que pudessemos receber de outros HOCs. E isso deveria ser feito em todos os HOCs.

Mas o pior de tudo, na minha opinião, é que HOCs não resolvem o problemas da indireção.

Render Props

Uma das soluções propostas pare resolver esses problemas é a técnica chamada de render props. O que muda, nessa técnica, em relação aos HOCs, é que em vez de renderizar o componente que veio como ‘parâmetro’ a gente chama uma função passando o que a gente quer compartilhar e usa o retorno dessa função no render.

De novo, é mais fácil olhando o código:

A única coisa que muda no Counter (agora chamado WithCounter) é o render, onde a gente executa a função que será passada como children e passa count e handleClick como parâmetros.

O App fica assim:

Não muda muita coisa, mas agora fica perfeitamente claro da onde count e handleClick estão vindo!

A gente ainda evita os problemas de colisão de nomes, já que podemos renomear os parâmetros para o que a gente quiser.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade