Container & Presentational Pattern - React
Tags: react, designpatterns, javascript
Published: 2023-06-20 15:00:33

Os padrões de design ou _design patterns_ tem como objetivo trazer ao projeto organização, legibilidade e como o próprio nome diz, **padrões**.

Esse é o primeiro artigo de uma série de como fazer uso de _design patterns_ em projetos, especificamente usando React. E para começar vamos considerar o _pattern_ que chamamos de **Container/Presentational Pattern**.

Tanto o _container_ quanto o _presentational_ são componentes, mas a forma com que eles trabalham são diferentes e tem como principal objetivo separar as responsabilidades. Com esse _pattern_ nós podemos separar a responsabilidade da visualização da responsabilidade da lógica da aplicação.

Caso ainda essa explicação esteja nebulosa em sua mente, vamos as considerações e exemplos.

## Container

> São componentes que em sua responsabilidade está em **como** os dados são apresentados na interface. A principal função dos _container components_ é passar os dados para os _presentational components_.

### Princípios

1. De modo geral os _container components_ renderizam apenas os _presentational components_ que se relacionam com os dados que precisam ser apresentados por aquele componente;

2. Além disso, geralmente também esses componentes não recebem estilos, visto que apenas passam os dados para os componentes que realmente farão a renderização da interface - os _presentational components_;

3. O foco desse componente é no comportamento e funcionalidade da aplicação, como os métodos e lógicas;

4. O gerenciamento de estados fica concentrado nesse componente, assim como também o fluxo de dados. Caso precise usar _hooks_, variáveis e método de contexto esse é o componente que irá fazer isso;

5. Facilidade em usar e entender as dependências do componente, como outras bibliotecas.

## Presentational

> São componentes que em sua responsabilidade está em **o que ** mostrar na interface. A principal função dos _presentational components_ é mostrar os dados que são recebidos.

### Princípios

1. Os dados são passados do _container_ para os _presentational_ por meio de _props_;

2. Esses dados não são modificados no _presentational_, apenas exibidos. Se precisar alterar os dados faça isso dentro do _container components_;

3. É um _stateless component_. Isto é, ele não gerencia nenhum estado, ou se gerenciar, que seja algo muito pontual;

4. Recebe os dados exclusivamente por meio de _props_ do _container_.

---

Essa é uma imagem que representa esse design pattern, com um mínimo de lógica - um _fetch_ de dados que é feito dentro do _container_ e passado por props para dentro do _presentational_.

![Fluxograma do Container/Presentational Component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3kqxqcyj3tg5etxfsbtp.png)

---

## Show me the code

### Container

```javascript
import { useState, useEffect } from 'react';
import { PresentationalComponent } from './PresentationalComponent';

const ContainerComponent = () => {
  const [data, setData] = useState([]);

  function handleFetch() {
    fetch("https://randomuser.me/api")
      .then((response) => response.json())
      .then((data) => setData(data));
  }

  useEffect(() => {
    handleFetch();
  }, []);

  return (
      <PresentationalComponent 
         {...data} 
         handleFetch={handleFetch} 
      />
   );
};
```

Como mostra o código acima, a lógica, métodos e estados ficam dentro do _container component_. E os dados que precisam ser apresentados em tela se passa por _props_ para dentro do _presentational component_, assim como também os métodos.

### Presentational

```javascript
const PresentationalComponent = ({ 
   name, 
   email, 
   location, 
   handleFetch 
}) => {
  return (
    <Profile>
      <Info>{name.first}</Info>
      <Info>{email}</Info>
      <Info>
        {location.city}, {location.state}
      </Info>
      <Button onClick={handleFetch}>Buscar</Button>
    </Profile>
  );
};

```

E como mostra o código acima, o objetivo do componente é apenas exibir os dados e se possível praticamente mais nada deve ser de sua responsabilidade.

```
.
├── ...
├── components
    ├── ExampleComponent
        ├── container
            ├── index.tsx
        ├── presentational
            ├── index.tsx
        index.tsx
```

Para extrair o máximo de vantagens desse _design pattern_ procure utilizar a convenção de nomenclatura de pastas e de arquivos em todo o projeto. Fazer assim vai facilitar o entendimento da aplicação e ajudará na manutenção dos componentes.

Note que há um arquivo _index_ na raiz da pasta do componente. Esse arquivo tem como objetivo apenas exportar o _container_. É esse arquivo _index_ que podemos usar para chamar o _container component_ na aplicação. 

```javascript
export { ContainerComponent as Container } from './container';
```

Talvez seja redudante e a comunidade reclama da quantidade de arquivos que se cria nesse _design pattern_. Pode ser que esse seja um dos ônus de usar esse _pattern_. Mas particularmente, não me importo com isso. 

Acredito que essa convenção é mais para o desenvolvedor se localizar dentro do mundo das pastas de um projeto enorme por meio da IDE. 

> **O ideal é nunca exportar o _presentational component_ em qualquer arquivo que não seja o _container component_ no qual ele está relacionado.**

Além disso, poderá criar testes unitários de forma mais fácil para os dois tipos de componentes. Para isso mantenha o componente de apresentação o mais simples possível focando na renderização de propriedades e chamadas de métodos. Assim, o arquivo vai ficar mais limpo e legível.

Pode ser que com o tempo o _container_ comece a ficar grande ou complexo. Antes disso acontecer, estude utilizar hooks e contexto para fazer a busca (fetch) de dados da API ou outro gerenciamento de estado que possa ser utilizado em toda a aplicação.

Dessa forma também, o _container_ ficará mais limpo e legível.

## Exemplo com hooks

### Hooks

```javascript
import { useState, useEffect } from 'react';

const useFetchUser = () => {
  const [data, setData] = useState([]);

  function handleFetch() {
    fetch("https://randomuser.me/api")
      .then((response) => response.json())
      .then((data) => setData(data));
  }

  useEffect(() => {
    handleFetch();
  }, []);

  return {
    handleFetch,
    data
  }
};
```

### Container

```javascript
import useFetchUser from '@hooks/useFetchUser';
import { 
   PresentationalComponent 
} from './PresentationalComponent';

const ContainerComponent = () => {
  const { data, handleFetch } = useFetchUser();

  return (
      <PresentationalComponent 
         {...data} 
         handleFetch={handleFetch} 
      />
   );
};
```

O arquivo ficou menor e o _presentational component_ permanece da mesma forma.

### Minhas considerações

Esse _design pattern_ pode ser substituído por muitos outros, diria eu, até melhores e mais fáceis de trabalhar visando os mesmos princípios explicados e mostrados aqui. Porém, esse artigo foi criado não com o objetivo de incentivar o uso desse _pattern_, mas por razões acadêmicas e seculares.

**Pode ser que você encontre um projeto assim em seu trabalho e provavelmente terá que seguir esses padrões, visto custar tempo, dinheiro e até mesmo experimentar riscos para mudar esse padrão.**

Em resumo, não aplique esse _design pattern_ em todo projeto que começar de maneira deliberada. Avalie bem a necessidade, motivação e conhecimentos técnicos seus e do time antes de decidir qual arquitetura usar no projeto. 

Pode ser que você encontre artigos em que ao invés dos nomes _container_ e _presentational_, sejam _smart_ e _dumbs_, mas como até diz no arquivo de referência do Dan, esses nomes não explicam nada.

## Referências

1. [Dan Abramov](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 )
2. [@lydiahallie & @addyosmani](https://www.patterns.dev/posts/presentational-container-pattern)