Image for post
Image for post
Cada pedaço é responsável por uma função, será que podemos aplicar programação funcional?

O futuro do React — setState e

programação funcional

React popularizou um paradigma de "programação funcional" em JavaScript. Isso liderou uma onda gigante de frameworks usando o padrão “baseado em componentes”, a-lá React. Agora, a febre sobre programação funcional está caindo sobre o boa parte do ecossistema de desenvolvimento web.

O ecossistema JavaScript está saindo de "um novo framework por semana" para "novo (e mais rápido) clone do React da semana" — Sylvain Wallez, tweet acima

Mas a equipe do React está longe de estar parada. Eles continuam indo a fundo, descobrindo ainda mais padrões de programação funcional escondidos na biblioteca.

Hoje, eu quero revelar um segredo que estava bem guardado dentro do React, funcional setState.

Usando as palavras do Dan Abramov para descrever esse padrão, funcional setState é descrito como:

Declare as mudanças de estado separadamente do seu componente…

Oi? Como é?

Bora esclarecer isso!

O que você já sabe

React é uma biblioteca baseada em componentes. Um componente é uma função que aceita algumas propriedades e retorna um elemento da UI.

Um componente pode precisar ter e precisar controlar seu próprio estado. Nesse caso, você irá precisar de uma classe. Sendo assim, você tem o estado do componente vivendo dentro da função constructor :

Para controlar o estado, React disponibiliza um método especial chamado setState(). Você usa ele assim:

Perceba como setState() funciona. Você passa um objeto contendo as partes do estado que você quer atualizar.

Em outras palavras, o objeto que você passa, terá chaves que correspondem as chaves do estado do seu componente, então setState() irá atualizar (ou setar) o estado, mergeando o objeto passado com o estado.

Afinal, “set-State”, duh!

O que você provavelmente não sabe

Lembrando minha explicação acima sobre setState(). E se eu te disser que, ao invés de passar um objeto, você pode passar uma função?

Sim. setState() também aceita uma função. Essa função recebe o antigo estado e as atuais props do componente, que geralmente são usadas para calcular e retornar o próximo estado. Mais ou menos assim:

Perceba que setState() é uma função, e nós estamos passando outra função como argumento (programação funcional…funcional setState).

De primeira, isso parece muito estranho, certo? Muitas etapas para apenas mudar o estado. Porque raios eu vou querer usar essa sintaxe?

Qual o motivo de usar função no setState?

O ponto principal é, atualizações de estado, podem acontecer assincronamente.

Vamos pensar no que acontece quando setState() é chamado.

Primeiramente, React irá mergear o objeto que você passar para setState() com o estado atual. Então, ele vai iniciar a parte de reconciliação do DOM. Ele vai criar uma nova árvore de elementos React (um objeto grande representando sua UI), irá comprar a árvore antiga com a nova, e descobrir o que exatamente mudou baseado no objeto que você passou em setState(), e finalmente, irá atualizar o DOM.

Eita, nossa! Quanto trabalho está envolvido nisso? Na verdade, isso é apenas uma síntese do que realmente acontece. Mas, acredite, React faz um ótimo trabalho nisso!

Em React, “set-state” não é tão simples assim

Devido ao tamanho do trabalho envolvido nessa etapa, chamar setState() não necessariamente irá atualizar seu estado imediatamente.

React pode realizar múltiplas chamadas a setState() em apenas um lote. Ou seja, realizando uma única atualização, para motivos de performance.

Mas o que React quer dizer com isso?

Primeiro, …múltiplas chamadas a setState()…, pode significar chamar setState() dentro de uma mesma função mais de uma vez, algo como:

Agora, quando React encontra múltiplas chamadas a setState(), ao invés de “setar-o-estado” três vezes, React irá evitar esse enorme trabalho, que eu descrevi acima, e malandramente irá dizer:

Opa, pera ae! Eu não vou atualizar três vezes, é um enorme trabalho atualizar o estado. O que eu vou fazer é empacotar todas essas chamadas juntas e atualizar apenas uma vez!

E isso meu amigos, é chamado de atualização em lotes (em inglês, batch updates ou batching).

Vamos lembrar uma coisa, nesse caso, nós estamos passando um objeto para setState(). Agora, vamos assumir que, a qualquer momento que React encontrar múltiplas chamadas a setState(), ele realiza a atualização em pacotes, extraindo todos os objetos passados para setState() mergeando eles juntos para formar um único objeto, para então, usar esse objeto para atualizar o estado.

Em JavaScript, “mergear” objetos se parece com:

Esse padrão é conhecido como composição de objetos.

Em JavaScript, o modo que a composição de objetos funciona é: se os três objetos em questão, tiverem a mesma chave, o valor da chave do último objeto passado será atribuída no objeto final. Por Exemplo:

Devido you ser o último objeto mergeado em we, o valor de name é atribuido da chave de you — “Meu Nome” — sobrescrevendo os valores do objeto me.

Portando, se você chamar setState() usando um objeto como parâmetro múltiplas vezes — React irá mergear em um único. Ele irá compor um novo objeto a partir dos múltiplos objetos passados. E se os objetos conterem as mesmas chaves, o valor do último objeto é o que prevalecerá. Certo?

Isso significa que, a função do exemplo acima, increaseScoreBy3, o resultado final do estado será incrementado apenas por 1, e não 3. Lembra que React não atualiza o estado imediatamente quando chamamos setState()?

Malandramente ele irá atualizar em lotes, então, quando chamamos múltiplas vezes :

{score : this.state.score + 1}

React irá compor esses objetos em apenas um, tendo um resultado final como:

User.setState({score : this.state.score + 1}).

Sendo super claro, passar um objeto para setState() não é um problema aqui.

O problema é passar um objeto para setState() quando você precisa calcular o próximo estado baseado no estado antigo.

Pare de fazer isso, não é seguro!

this.props e this.state podem ser atualizados assincronamente, você não deveria contar com seus valores para calcular seu próximo estado.

Sophia Shoemaker criou um CodePen bem maneiro sobre isso. Recomendo você dar uma olhada nas duas implementações e prestar atenção na solução correta e incorreta:

Preste atenção em ambas as soluções desse CodePen…

Funcional setState ao resgate!

Se você não passou um tempo brincando com o CodePen acima, eu recomendo você gastar uns minutos, ele irá te ajudar a entender o principal conceito desse artigo.

Olhando o CodePen acima, você percebe que funcional setState realmente resolve o problema.

Mas isso não é o bastante, queremos saber o como!

Vamos consultar o Ronaldo Fenomeno do React — Dan.

É seguro chamar setState com função múltiplas vezes. Atualizações serão enfileiradas e executas posteriormente em ordem de chamada. — Dan Abramov, tweet acima

Preste atenção na resposta que ele deu. Quando você usa funcional setState:

Atualizações serão enfileiradas e executas posteriormente em ordem de chamada.

Quer dizer que, quando React encontra múltiplas chamadas a funcional setState(), ao invés de mergear os objetos (meio óbvio, não existe objeto nesse caso, estamos passando uma função!), React irá criar uma fila de funções baseado na ordem em que foram chamadas.

Depois disso, React irá atualizar o estado chamando cada função da fila, passando o antigo estado — na verdade, só se essa chamada for a primeira da fila, as chamadas decorrentes, receberam o estado baseado no resultado da última função chamada dessa fila de funcional setState().

Ainda em dúvida? Vamos olhar algum código para esclarecer essa idéia. Dessa vez, vamos criar um pseudo-código para explicar a idea das partes internas do React.

Primeiramente, vamos criar um componente usando classe. Dentro dele, vamos criar um estado, e também um método increaseScoreBy3(), quer irá conter múltiplas chamadas a funcional setState. Finalmente, nós vamos instanciar essa classe, exatamente como React faria:

Agora, quando chamarmos increaseScoreBy3(), React irá criar uma fila com as chamadas múltiplas. Não vamos criar essa lógica aqui, queremos focar apenas no que torna o funcional setState seguro. Mas, podemos imaginar que o resultado dessa chamada cria algo como:

Finalmente, um pseudo-código de como o estado seria atualizado:

Mesmo em pseudo-código, não é tão bonito. Mas o ponto principal aqui é que, toda vez que React executa uma função vinda de uma chamada funcional setState, React atualiza o estado passando uma cópia atualizada do estado. Isso torna possível para chamadas funcionais ao setState atualizarem o estado baseado na chamada anterior de atualização de estado.

Talvez no JSBin fique mais claro, você pode brincar com o pseudo-código lá para entender a idéia:

Recomendo gastar uns minutos lá para entender bem o que acontece.

Agora, vamos ver exemplos do porque isso é um pedaço de ouro!

O segredo bem guardado do React

Até agora, nós analisamos a parte interna do React, e o porque é seguro usar múltiplas chamadas a funcional setState. Mas ainda não exploramos o que isso muda no nosso trabalho diário.

Lembrando o que o Dan disse:

Declare as mudanças de estado separadamente do seu componente

Durante os anos, a lógica de setar um estado — isso é, as funções ou objetos que passávamos para setState() — sempre viviam dentro da classe do componente. Isso é mais imperativo do que declarativo.

Hoje, eu quero mostrar mais uma parte desse segredo bem guardado em React:

Um segredo bem guardado do React: Você pode declarar mudanças de estado separadamente do seu componente. — Dan Abramov, tweet acima.

Obrigado Dan Abramov!

Esse é o poder de funcional setState. Declarar a lógica de atualização fora do seu componente. E chama-lá dentro dele:

Isso é declarativo! Seu componente não mais se importa em como o estado deve ser atualizado. Ele simplesmente declara o tipo de atualização que ele deseja.

Para realmente apreciar isso, imagine em todos aqueles componentes complexos que contem vários pedaços de estado, atualizar cada estado em diferente ações. E algumas vezes, cada atualização requer linhas e linhas de código. Toda essa lógica iria viver dentro do seu componente. Agora, não mais!

Aliás, falando me organização, eu gosto de manter cada módulo o mais pequeno possível, agora, extraindo a lógico dos seus componentes, passa aquela sensação de “isso não deveria estar aqui”. Agora você tem o poder de extrair toda sua lógica de atualização para um módulo diferente, importar e usá-la no seu componente.

Você pode até mesmo reusar increaseScore em outro componente. Só importar :)

O que mais você pode fazer com funcional setState?

Testes ficam muito mais fáceis!

Declarar atualizações de estado como funções puras, torna simples o teste de atualizações complexas. E não é nem preciso utilizar shallow rendering!

Você pode até passar argumentos extras para calcular o próximo estado. (É #FunFunFunction galera!)

E se você precisar passar um argumento extra para calcular o próximo estado? Funções podem retornar funções 😉 — Dan Abramov, tweet acima

E te digo, espere ainda mais em…

O Futuro do React

Há anos, a equipe do React tem experimentado a melhor maneira de implementar funções com estado.

Funcional setState parece a resposta exata para isso! (Ou provavelmente é).

Voltamos ao nosso Ronal fenômeno, alguma nota final?

Certamente React irá suportar esse estilo mais diretamente no futuro. Eu recomendo você tentar usar e ver se gosta!

Se você chegou até aqui, você está tão animado quanto eu!

Recomendo você começar a experimentar funcional setState hoje! (Pega umdois componentes e booom!)

Se você acho que fiz um bom trabalho com esse artigo, ou que aquele seu amigo dev deveria ler isso também, clica no coração verde abaixo e ajude a espalhar um melhor conhecimento sobre React na nossa comunidade.

Se você tiver qualquer pergunta que não foi respondida ou você não concorda com algo, é só deixar um comentário ou me mandar um tweet!

Happy Coding galera!

Créditos

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store