React: Guia Visual para o Modelo Mental do React, Parte 2 - useState, useEffect e ciclos de vida
Tags: ptbr, react, webdev, beginners
Published: 2020-09-23 07:46:37

Eu amo modelos mentais. Eles são cruciais para a compreensão de sistemas complexos, nos permitindo compreender e resolver problemas complexos de forma intuitiva.

Este é o segundo de uma série de três artigos sobre os modelos mentais do React. Vou **mostrar** os modelos mentais exatos que uso com complexos componentes React, construindo-os do zero e usando várias explicações visuais.

Recomendo que você leia a [parte 1](https://dev.to/oieduardorabelo/react-guia-visual-para-o-modelo-mental-do-react-2864) primeiro, pois os modelos mentais neste artigo se baseiam nos que expliquei lá. Se você quiser uma atualização, [aqui está o modelo mental completo para a parte 1](https://dev.to/oieduardorabelo/react-guia-visual-para-o-modelo-mental-do-react-2864#um-modelo-mental-completo-do-react-reunindo-tudo)

> Mesmo que você já trabalhe com o React há anos ou esteja apenas começando, ter um modelo mental útil é, na minha opinião, é a maneira mais rápida de se sentir confiante trabalhando com ele.

Você vai aprender:

-   **O hook useState** : Como ele _magicamente_ funciona e como entendê-lo intuitivamente.
-   **O ciclo de vida do componente: montagem, renderização, desmontagem** : a fonte de muitos bugs é a falta de um bom modelo mental em torno deles.
-   **O hook useEffect** : como esse gancho poderoso realmente funciona?

Vamos começar!

## O Que São Modelos Mentais E Por Que São Importantes?

Um modelo mental é um processo de pensamento ou imagem mental que nos ajuda a compreender sistemas complexos e a resolver problemas difíceis intuitivamente, guiando-nos na direção certa. Você usa modelos mentais todos os dias; pense em como você imagina que a Internet, os carros ou o sistema imunológico funcionem. Você tem um modelo mental para cada sistema complexo com o qual interage.

## O Modelo Mental Para React Até Agora

Aqui está uma visão geral rápida do modelo mental do React que expliquei na parte 1, ou você pode encontrar [a versão completa da parte 1 aqui](https://dev.to/oieduardorabelo/react-guia-visual-para-o-modelo-mental-do-react-2864#um-modelo-mental-completo-do-react-reunindo-tudo) .

Um componente React é como uma função, ele recebe `props` das quais são os argumentos de uma função e será executado novamente sempre que essas props mudarem. Eu imagino um componente como uma caixa que vive dentro de outra caixa.

Cada caixa pode ter muitos filhos, mas apenas um pai, e além de receber `props` de seu pai, ela tem uma variável interna especial chamada `state`, que também a re-executa (re-renderizada) quando muda.

[![Modelo mental de uma re-renderização do componente React quando props ou mudança de estado acontecem, mais limpo do que na parte 1](https://obedparla.com/static/1c6caf6685f0bd3381d84a8166579de1/7efee/react-rendering-mental-model-from-part1-cleaner.jpg "Quando props ou estado mudam, o componente é renderizado novamente")](https://obedparla.com/static/1c6caf6685f0bd3381d84a8166579de1/ea2ac/react-rendering-mental-model-from-part1-cleaner.jpg)

Quando adereços ou estado muda, o componente é renderizado novamente

## O hook useState: Estado Em Uma Garrafa

Mostrei [como o estado funciona na parte 1](https://dev.to/oieduardorabelo/react-guia-visual-para-o-modelo-mental-do-react-2864#colocando-o-estado-do-react-ao-nosso-modelo-mental) e como ele é uma propriedade especial dentro de uma caixa. Ao contrário das variáveis ​​ou funções que são declaradas novamente em cada renderização, os valores que saem do `useState` sempre são consistentes entre as renderizações. Eles são inicializados no `mount` com um valor padrão e só podem ser alterados por um evento `setState`.

Mas como o React pode evita que o `state` perca seu valor em cada renderização?

A resposta é: o **escopo**.

Expliquei o modelo mental para [closures e escopo no passo 1](https://dev.to/oieduardorabelo/react-guia-visual-para-o-modelo-mental-do-react-2864#closures-em-react) . Em suma, uma closure é como uma caixa semipermeável, permitindo a entrada de informações de fora, mas nunca vazando nada.

[![Um modelo mental para Closures em JavaScript, mostrando diferentes aplicativos React e scripts como caixas em Global / Window](https://obedparla.com/static/e0caedb67992235db77271808958da3d/8a6f5/javascript-closure-mental-model.jpg "Closures em JavaScript visualizados")](https://obedparla.com/static/e0caedb67992235db77271808958da3d/8a6f5/javascript-closure-mental-model.jpg)

Com `useState`, React define seu valor para a closure mais externa, que é o aplicativo React que contém todos os seus componentes. Em outras palavras, sempre que você usa o `useState`, React retorna um valor que é armazenado _fora do_ seu componente e, portanto, não muda em cada renderização.

O React consegue fazer isso acompanhando cada componente e a ordem em que cada hook é declarado. Essa é a razão pela qual você não pode ter um React Hook dentro de uma condicional. Se useState, useEffect ou qualquer outro hook for criado _condicionalmente_ , o React não poderá controlá-lo adequadamente.

Isso é melhor explicado visualmente:

[![Modelo mental do escopo do estado do React, mostrando uma caixa com o estado vivendo na caixa externa e não na caixa de componentes](https://obedparla.com/static/12ed0cadb923354ab1d89aa87165d055/86435/react-state-scope-mental-model.jpg "O estado do React tem como escopo a caixa mais externa, dessa forma não muda em cada renderização")](https://obedparla.com/static/12ed0cadb923354ab1d89aa87165d055/86435/react-state-scope-mental-model.jpg)

Sempre que um componente é renderizado novamente, `useState` pede o estado do componente atual, o React verifica uma lista contendo todos os estados de cada componente e retorna o valor correspondente. Esta lista é armazenada fora do componente porque em cada uma das variáveis ​​de renderização e funções são criadas e destruídas em cada renderização.

Embora esta seja uma visão técnica de como o estado funciona, ao compreendê-la, posso transformar parte da magia do React em algo que posso visualizar. Para meu modelo mental, eu costumo simplificar as coisas em uma ideia mais simples.

Meu modelo mental ao trabalhar com `useState`é este: uma vez que o estado não é afetado pelo que acontece com a caixa, imagino-o como um valor constante dentro dela. Eu sei que não importa o que aconteça, o `state` permanecerá consistente durante toda a vida útil do meu componente.

[![Modelo mental de um componente React com estado, o estado como uma constante no topo da caixa](https://obedparla.com/static/0843a9f87a69f2084ec10f3bb8ebf061/87d62/react-state-mental-model-detailed.jpg "O estado permanece constante, embora o componente possa mudar")](https://obedparla.com/static/0843a9f87a69f2084ec10f3bb8ebf061/87d62/react-state-mental-model-detailed.jpg)

O estado permanece constante, embora o componente possa mudar

### Como O Estado Muda?

Depois de entender como o estado é preservado, é importante entender como ele muda.

Você pode saber que as atualizações de estado são `async`, mas o que isso significa? Como isso afeta nosso trabalho diário?

Uma explicação simplificada de `sync`e `async`é:

-   Código **síncrono**: que bloqueia a thread do JavaScript, onde seus aplicativos são executados, impedidos de fazer qualquer outro trabalho. Apenas um trecho de código pode ser executado por vez no segmento.
-   Código **assíncrono**: que não bloqueia o thread porque ele é movido para uma fila e executado sempre que houver tempo disponível.

Usamos o estado como uma variável, mas a atualização é `async`. Isso torna mais fácil cair na armadilha de pensar que um `setState` mudará seu valor imediatamente como faria uma variável, o que leva a bugs e frustração, por exemplo:

```jsx
const Component = () => {
  const [searchValue, setSearchValue] = useState('');

  // procura alguma coisa quando o usuário escreve no inout
  const handleInput = e => {
    // salva o valor no estado e em seguida, o usa para buscar novos dados ❌
    setSearchValue(e.target.value);
    fetchSearch(searchValue).then(results => {
      // faz algo
    });
  };
};
```

Este código está cheio de erros. Imagine uma pessoa digitar **Bye**. O código procurará por **By** vez de **Bye** porque cada nova digitação aciona um novo `setSearchValue`e `fetchSearch`, mas como as atualizações de estado são `async`, vamos buscar com um valor desatualizado para `searchValue`. Se uma pessoa digitar rápido o suficiente e tiver outro código JavaScript em execução, podemos até pesquisar apenas por **B** pois o JavaScript ainda não teve tempo de executar o código que está na fila.

Resumindo, não espere `state` ser atualizado imediatamente. Isso corrige o bug:

```javascript
const Component = () => {
  const [searchValue, setSearchValue] = useState('');

  const handleInput = e => {
    // salvamos o valor pesquisado em uma variável antes de usar ✅
    const search = e.target.value;
    setSearchValue(search);
    fetchSearch(search).then(results => {
      // do something
    });
  };
};
```

Um dos motivos pelos quais as atualizações de estado são `async` é para otimizáção. Se um aplicativo tiver centenas de estados diferentes que desejam atualizar de uma só vez, o React tentará agrupar o maior número possível em uma única operação `async`, ao invés de executar muitos eventos `sync`. As operações assíncronas, em geral, também têm melhor desempenho.

Outro motivo é a consistência. Se um estado for atualizado muitas vezes em rápida sucessão, o React usará apenas o valor mais recente por uma questão de consistência. Isso seria difícil de fazer se as atualizações fossem `sync` e executadas imediatamente.

[![Um modelo mental de como as threads em JavaScript funcionam com estado, React agrupa atualizações de estado](https://obedparla.com/static/a0da8e6bee48daa6f697cd94023a9736/7efee/async-state-updating-mental-model.jpg "Um modelo mental de como as threads em JavaScript funcionam com estado, React agrupa atualizações de estado")](https://obedparla.com/static/a0da8e6bee48daa6f697cd94023a9736/fe1e7/async-state-updating-mental-model.jpg)

Em meu modelo mental, vejo os valores de estados individuais sendo confiáveis, mas lentos. Sempre que atualizo um, sei que pode demorar um pouco para que ele mude.

Mas o que acontece com o estado e o próprio componente, quando ele é montado e desmontado?

## Ciclo De Vida De Um Componente: Modelos Mentais Para Montagem, Renderização E Desmontagem

Anteriormente, falávamos muito sobre **métodos de ciclo de vida**, quando apenas os componentes de classe tinham acesso a `state` e controle do que estava acontecendo com um componente durante sua vida. Mas desde que os Hooks surgiram, nos permitindo o mesmo tipo de poder em componentes funcionais, a ideia se tornou menos relevante.

O interessante é que cada componente ainda tenha um ciclo de vida: é montado, renderizado e desmontado, e cada etapa deve ser levada em consideração para um modelo mental totalmente funcional em torno dos componentes React.

Portanto, vamos passar por cada fase e construir um modelo mental para isso, prometo que tornará sua compreensão de um componente muito melhor.

### Montagem: Criando Componentes

Quando o React cria ou renderiza um componente pela primeira vez, é a fase de `mounting` dele. O que significa que será adicionado ao DOM e o React começará a controlá-lo.

Gosto de imaginar `mounting` como uma nova caixa sendo e/ou adicionada dentro de seu pai.

A montagem acontece sempre que um componente que não foi renderizado ainda, e o seu componente pai decide renderizá-lo pela primeira vez. Em outras palavras, `mounting`é quando um componente que está "nascendo".

Um componente pode ser criado e destruído muitas vezes e, a cada vez que for criado, ele será montado novamente.

```jsx
const Component = () => {
  const [show, setShow] = useState(false);

  return (
    <div>
      <button onClick={() => setShow(!show)}>Show Menu</button>
      // Montando com `show = true` e desmontado com `show = fase`
      {show && <MenuDropdown />}
    </div>
  );
};
```

O React renderiza componentes tão rápido que pode parecer que ele está os escondendo, mas na realidade, ele os cria e exclui muito rapidamente. No exemplo acima, o componente `<MenuDropdown />` será adicionado e removido do DOM sempre que o botão for clicado.

Observe como o pai do componente é quem decide quando montar e desmontar `<MenuDropdown />`. Isso é a hierarquia de componentes. Se `MenuDropdown`tiver componentes filhos, eles serão montados ou desmontados também. O próprio componente nunca sabe quando será montado ou desmontado.

[  
![Duas caixas próximas uma da outra representando o modelo mental de um componente React montando um componente filho quando a lógica muda.  O componente a ser montado é mostrado com baixa opacidade à esquerda](https://obedparla.com/static/6f51402353470d70615fd47245b551fe/7efee/component-mount-mental-model.jpg "O componente pai é renderizado novamente com uma lógica diferente, fazendo com que um filho monte")](https://obedparla.com/static/6f51402353470d70615fd47245b551fe/4eadb/component-mount-mental-model.jpg)

Uma vez que um componente é `mounted` (montado), ele fará algumas coisas:

-   Inicializar `useState` com os valores padrão: isso _só acontece_ na montagem.
-   Executa a lógica do componente.
-   Faz uma renderização inicial, adicionando os elementos ao DOM.
-   Executa o hook `useEffect`.

Observe que o `useEffect` é executado _após a renderização inicial_. É quando você deseja executar o código, como a criação de ouvintes de eventos (_event subscribers_), a execução de lógica pesada ou a obtenção de dados (_data fetching_). Mais sobre isso na seção useEffect abaixo.

Meu modelo mental para `mounting`é o seguinte: sempre que uma caixa pai decide que um filho deve ser criado, ele a **monta**, então o componente fará três coisas: atribuir valores padrão a `useState`, executar sua lógica, renderizar e executar o hook `useEffect`.

A fase de `mount` é muito semelhante a um normal `re-render`, com a diferença de inicializar `useState` com valores padrão e os elementos sendo adicionados ao DOM pela primeira vez. Depois que o componente realiza o `mount`, ele permanece no DOM e é atualizado posteriormente.

Uma vez que um componente é montado, ele continuará funcionando até que seja desmontado, fazendo qualquer quantidade de renderizações entre eles.

### Renderizando: Atualizando O Que O Usuário Vê

Expliquei [o modelo mental de renderização na parte 1](https://dev.to/oieduardorabelo/react-guia-visual-para-o-modelo-mental-do-react-2864#o-modelo-mental-de-renderiza%C3%A7%C3%A3o-compreendendo-a-magia-do-react), mas vamos revisá-lo brevemente, pois é uma fase importante.

Depois que um componente é montado, quaisquer alterações em `props` ou `state` farão com que seja renderizado novamente, re-executando _todo_ o código dentro dele, incluindo seus componentes filhos. Depois de cada `render` o hook `useEffect` é avaliado novamente.

Imagino um componente como uma caixa e sua capacidade de renderizar novamente o torna uma caixa reutilizável. Cada render recicla a caixa, o que poderia gerar informações diferentes, mantendo o mesmo estado e código por baixo.

[![Modelo mental de montagem de um componente, mostrando 3 caixas em 3 estágios: o componente inicial, props / mudança de estado causando uma nova renderização e novo componente](https://obedparla.com/static/648e36d88ac2ea2557026e0cad8117d2/7efee/rerendering-mental-model-part2.jpg "Um componente é renderizado novamente sempre que o estado ou os props mudam, ou seu pai é renderizado novamente")](https://obedparla.com/static/648e36d88ac2ea2557026e0cad8117d2/ea2ac/rerendering-mental-model-part2.jpg)

Uma vez que o pai de um componente decide parar de renderizar um filho - por causa de uma condição, mudanças nos dados ou qualquer outro motivo - o componente precisará ser desmontado.

## Desmontagem: Excluindo Componentes

Quando a fase de `unmounted` em um componente é ativado, o React o remove do DOM e para de controlá-lo. O componente é excluído, incluindo qualquer `state` que ele tinha

Como explicado na fase de `mounting`, um componente é ao mesmo tempo `mounted` e `unmounted` por seu pai, e se o componente, por sua vez, tiver filhos, eles também terão a fase de `unmount`, e o ciclo se repete até que o último filho seja alcançado.

Em meu modelo mental, vejo isso como uma caixa-pai destruindo suas caixas-filhos. Se você jogar um contêiner no lixo, tudo dentro dele também irá para o lixo, isso inclui outras caixas (componentes), estado, variáveis, tudo.

[![Duas caixas próximas uma da outra representando o modelo mental de um componente React desmontando um componente filho quando a lógica muda.  O componente a ser desmontado é mostrado com baixa opacidade à direita](https://obedparla.com/static/2a02814a6135948c37ecb0cc8802eed3/7efee/component-unmount-mental-model.jpg "O componente pai é renderizado novamente com uma lógica diferente, fazendo com que um filho desmonte")](https://obedparla.com/static/2a02814a6135948c37ecb0cc8802eed3/4eadb/component-unmount-mental-model.jpg)

Mas um componente pode criar código _fora_ de si mesmo. O que acontece com qualquer assinatura (_subscription_), soquete da web (_websockets_) ou ouvinte de evento (_event listeners_) criado por um componente que será desmontado?

A resposta é nada. Essas funções são executadas fora do componente e não serão afetadas por sua exclusão. É por isso que é **importante que o componente seja limpo antes de desmontar**.

Cada função consome recursos. Deixar de limpá-los pode levar a bugs desagradáveis, desempenho degradado e até riscos de segurança.

Eu penso nessas funções como engrenagens girando fora da minha caixa. Eles são colocados em movimento quando o componente monta e devem ser interrompidos quando desmontados.

[![Duas caixas nas laterais com ícones de engrenagem no meio.  Um modelo mental para funções externas que não são afetadas pela desmontagem do componente React](https://obedparla.com/static/16c28a719ac6eda87f961b42316b1ab9/7efee/mental-model-of-mounting-external-functions.jpg "Uma função que reside fora do seu código não será removida na fase de desmontar por conta própria.")](https://obedparla.com/static/16c28a719ac6eda87f961b42316b1ab9/ae68a/mental-model-of-mounting-external-functions.jpg)

Podemos limpar ou parar essas engrenagens por meio da função de retorno do `useEffect`. Explicarei em detalhes na seção hook useEffect.

Então, vamos colocar todos os métodos de ciclo de vida em um modelo mental claro.

## O Modelo Mental Completo Do Ciclo De Vida Do Componente

Para resumir o que vimos até agora: um componente é apenas uma função, props são os argumentos da função e o estado é um valor especial que o React garante manter consistente entre as renderizações. Todos os componentes devem estar dentro de outros componentes e cada pai pode ter muitos filhos dentro dele.

[![Um modelo mental completo para um componente React com estado simples: uma caixa com props vindo de fora, estado de dentro na parte superior, lógica e componentes.](https://obedparla.com/static/083891c92c63c1c4240a602182c67277/44313/react-component-mental-model.jpg "Um modelo mental completo para um componente com estado simples")](https://obedparla.com/static/083891c92c63c1c4240a602182c67277/44313/react-component-mental-model.jpg)

Cada componente tem três fases em seu ciclo de vida: montagem, renderização e desmontagem.

Em meu modelo mental, um componente é uma caixa e com base em alguma lógica pode decidir criar ou excluir uma caixa-filho. Quando o cria, é um componente montado e quando o exclui, ele é desmontado.

Uma caixa montando significa que foi criada e executada. É aqui que `useState` é inicializado com os valores padrão e o React o renderiza para que o usuário possa vê-lo e também começa a controlá-lo.

A fase de montagem é onde nos conectamos a serviços externos, buscamos dados ou criamos escutadores de eventos (_event listeners_).

Uma vez montado, sempre que as pros ou estado de uma caixa mudarem, ela será refeita, o que eu imagino como a caixa sendo reciclada e tudo, _exceto o_ estado, é re-executado e re-calculado. O que o usuário vê pode mudar a cada nova renderização. A re-renderização é a segunda fase, que pode acontecer inúmeras vezes, sem limite.

Quando a caixa-pai de um componente decide removê-lo, seja por causa da lógica, o próprio pai foi removido ou os dados foram alterados, o componente o fará a fase de desmontagem.

Quando uma caixa desmontada é jogada fora, vai para o lixo com tudo o que contém, incluindo componentes filhos (que por sua vez têm os suas próprias fases de desmontagem). É aqui que temos a chance de limpar e excluir qualquer função externa inicializada em `useEffect`.

O ciclo de montagem, renderização e desmontagem pode acontecer milhares de vezes em seu aplicativo sem que você perceba. O React é incrivelmente rápido e é por isso que é útil manter um modelo mental em mente ao lidar com componentes complexos, já que é tão difícil ver o que está acontecendo em tempo real.

Mas como tiramos proveito dessas fases em nosso código? A resposta está no poderoso hook `useEffect` .

## O hook useEffect: Poder ilimitado!

O hook de efeito nos permite executar **efeitos colaterais** em nossos componentes. Sempre que você está buscando dados, conectando-se a um serviço ou assinatura ou manipulando manualmente o DOM, está realizando um efeito colateral (também simplesmente chamado de "efeito").

Um efeito colateral no contexto de funções é qualquer coisa que torne a função imprevisível, como dados ou estado. Uma função sem efeitos colaterais será previsível e _pura_ - você deve ter ouvido falar de `pure functions`- sempre fazendo exatamente a mesma coisa, desde que as entradas permaneçam constantes.

Um hook de efeito sempre é executado _após_ cada renderização. O motivo é que os efeitos colaterais podem conter lógica pesada ou demorar, como a obtenção de dados, portanto, em geral, é melhor executar após a renderização.

O hook recebe dois argumentos: a função a ser executada e um array com valores que serão avaliados após cada renderização, esses valores são chamados de dependências.

```javascript
// Opção 1 - sem dependências
useEffect(() => {
  // lógica pesada que roda depois de cada renderização
});

// Opção 2 - dependências vazias
useEffect(() => {
  // cria um escutador de eventos (event listener), inscrição (subscription)
  // ou busca dados uma única (fetch one-time data)
}, []);

// Opção 3 - com dependências
useEffect(() => {
  // busca dados sempre que A, B ou C mudarem
}, [a, b, c]);
```

Dependendo do segundo argumento, você tem 3 opções com comportamentos diferentes. A lógica de cada opção é:

-   **Se não estiver presente,** o efeito será executado após cada renderização. Esta opção não é normalmente usada, mas é útil em algumas situações, como a necessidade de fazer cálculos pesados ​​após cada renderização.
-   **Com um array vazio,**  `[]` o efeito é executado apenas uma vez, após a montagem e na primeira renderização. Isso é ótimo para efeitos únicos, como criar um escutador de eventos (_event listener_).
-   **Um array com valores**  `[a, b, c]` faz **com** que o efeito avalie as dependências, sempre que uma dependência mudar o efeito será executado. Isso é útil para executar efeitos quando _props_ ou o estado mudam, como buscar novos dados.

[  
![Três caixas coloridas que representam as três opções de arrays de dependência do hook useEffect: sem, vazio, com valores](https://obedparla.com/static/0698801bff1422709e0ad0ae3f76a2e2/ba295/use-effect-dependency-otpions.jpg "Uma explicação visual das opções de dependência de useEffect")](https://obedparla.com/static/0698801bff1422709e0ad0ae3f76a2e2/ba295/use-effect-dependency-otpions.jpg)

O array de dependência da ao `useEffect` sua mágica e é importante usá-la corretamente. Você _deve_ incluir todas as variáveis ​​usadas em `useEffect`, caso contrário, o efeito fará referência a valores obsoletos de renderizações anteriores durante a execução, causando bugs.

O plugin ESLint `eslint-plugin-react-hooks`contém muitas regras específicas de Hooks úteis, incluindo uma que irá avisá-lo se você perdeu uma dependência dentro de um `useEffect`.

Meu modelo mental inicial para useEffect é como ter uma mini-caixa dentro de seu componente, com três comportamentos distintos dependendo do uso do array de dependência: o efeito é executado após cada renderização se não houver dependências, apenas após a montagem se for um array vazio, ou sempre que uma dependência muda se o array tiver valores.

[![Três caixas que representam cada opção useEffect dentro de uma caixa de componente](https://obedparla.com/static/0fa496b7f696513c2b2470e1f2bd5fa1/8a6f5/use-effect-inside-component-model.jpg "Cada useEffect reside dentro do componente, acessando as mesmas informações, mas como sua própria caixa")](https://obedparla.com/static/0fa496b7f696513c2b2470e1f2bd5fa1/8a6f5/use-effect-inside-component-model.jpg)

Há outro recurso importante do `useEffect`, nos permite fazer a limpeza antes que um _novo_ efeito seja executado ou antes que a desmontagem ocorra.

### Limpeza: useEffect durante a desmontagem

Cada vez que criamos uma assinatura, escutador de eventos ou conexões abertas, devemos limpá-los quando não forem mais necessários, caso contrário, criamos um vazamento de memória e degradamos o desempenho de nosso aplicativo.

É aqui que `useEffect` vem a calhar. Ao retornar uma função dele, podemos executar o código antes de aplicar o próximo efeito ou, se o efeito for executado apenas uma vez, o código será executado antes da desmontagem do componente.

```javascript
// Esse efeito irá executar uma ver na montagem, criando um escutador de eventos
// Na fase de desmontagem, irá executar a função que está sendo retornada
// removendo o escutador de eventos e limpando nossa bagunça ✅
useEffect(() => {
  const handleResize = () => setWindowWidth(window.innerWidth);
  window.addEventListener('resize', handleResize);

  return () => window.remoteEventListener('resize', handleResize);
}, []);

// Esse efeito irá executar sempre que o valor de `props.stream.id` mudar
useEffect(() => {
  const handleStatusChange = streamData => {
    setStreamData(streamData);
  };

  streamingApi.subscribeToId(props.stream.id, handleStatusChange);

  // Cancela a inscrição do ID atual antes de executar o próximo efeito com novo ID
  return () =>
    streamingApi.unsubscribeToId(props.stream.id, handleStatusChange);
}, [props.stream.id]);
```

## O modelo mental completo do React Hook useEffect

Imagino o useEffect como uma pequena caixa dentro de um componente, vivendo ao lado da lógica do componente. O código desta caixa (chamado de efeito) só é executado depois que o React renderizou o componente, e é o lugar perfeito para executar efeitos colaterais ou alguma lógica pesada.

Toda a magia do useEffect vem de seu segundo argumento, o array de dependência, e pode ter três comportamentos a partir dela:

-   Sem argumento: o efeito é executado após cada renderização
-   Array vazio: o efeito só é executado após a renderização inicial e a função de retorno antes da desmontagem.
-   Array com valores: sempre que uma dependência muda, o efeito será executado e a função de retorno será executada _antes_ do novo efeito.

---

Espero que você tenha achado meus modelos mentais úteis! Tentar explicá-los foi claramente um desafio. Se você gostou de ler, compartilhe este artigo, é tudo o que peço ❤️.

Esta foi a segunda parte de uma série de três partes, a próxima e última, abordarão conceitos de alto nível, como React `context` e como pensar melhor em seu aplicativo para evitar problemas comuns de desempenho.

Estou planejando uma série de guias visuais. A melhor maneira de saber quando eles serão lançados é [assinar minha newsletter](https://obedparla.substack.com/). Eu só envio emails de artigos novos de alta qualidade.

Que perguntas você tem? Estou sempre disponível no [Twitter](https://twitter.com/ObedParla)!

# Créditos

- [A Visual Guide To React Mental Models, Part 2: UseState, UseEffect And Lifecycles](https://obedparla.com/code/a-visual-guide-to-react-mental-models-part-2-use-state-use-effect-and-lifecycles/), escrito originalmente por [Obed Parlapiano](https://twitter.com/obedparla).