🎨 Biblioteca immer: Melhorando a legibilidade do código
Trabalhando com estrutura de dados imutáveis no React
Antes de tudo, o que é imutabilidade ?
Imutabilidade é um conceito muito utilizado no React (e em outras bibliotecas ou paradigmas da programação) que prega a seguinte expressão: Algo que foi criado (um estado no React) não pode sofrer alteração.
Para o React, quando um estado sofre uma alteração, é mais benéfico/performático destruir tudo e construir o estado novamente, do que ficar verificando se um estado sofreu alteração toda hora, e quando isso ocorrer, atualizar seu valor.
Mas então como eu faço para alterar ou adicionar um valor em uma estrutura de dados, como um estado que armazena um array por exemplo ?
Já que não podemos alterar o valor, podemos substitui-lo por completo. Ou seja, em uma situação onde é necessário incluir um valor em um array, eu preciso substituir todos os valores desse array, passando uma nova lista com os valores antigos com adição do novo valor.
Exemplos
Inserção de um valor em um array de forma mutável
const postsTabNews = ["post1", "post2", "post3"]
postsTabNews.push("post4")
Inserção de um valor em um array de forma imutável (Exemplo utilizando um estado o React)
const [postsTabNews, setPostsTabNews] = useState(["post1", "post2", "post3"])
setPostsTabNews((state) => return [...state, "post4"])
Analisando o exemplo a cima utilizando a forma imutável, nós inicializamos o Estado contendo 3 valores, porém na necessidade de incluir um novo valor, nós passamos um novo array, contendo os valores inicias, e mais o valor que queremos adicionar.
Beleza Matheus, eu entendi, mas qual o problema em fazer dessa forma ?
Para quem está começando, essa sintaxe imutável, de ter que substituir os valores, e não atualizar, pode confundir. Nós estamos vendo um exemplo simples, apenas adicionando um valor no array, mas imagine ter um array com vários objetos, e estes possuirem várias propriedades, e eu preciso alterar o valor de uma propriedade nesse array ?
Biblioteca immer
E se eu dissesse que existe uma forma de trabalhar de forma mutável com estados, reducers, no React ?
Mas Matheus, você acabou de dizer que para o React é mais performático trabalhar de forma imutável, porque eu mudaria isso ?
Boa pergunta. Apenas a escrita do código será de forma mutável, mas por de baixo dos panos, esse código será convertido para um código imutável. Ou seja, você vai aproveitar o melhor dos dois mundos: A facilidade de entender o que está ocorrendo no estado (mutabilidade) sem comprometer a performance (imutabilidade). E quem fará isso por nós é uma biblioteca chamada immer.
O immer é muito útil quando temos um estado complexo, pois com ele conseguimos escrever com a sintaxe mutável, tornando mais claro o que está sendo feito determinado código.
Exemplos
Alterando uma propriedade sem utilizar o immer
const Tasks = [
{
name: "Estudar",
done: false
}
{
name: "Jogar videogame",
done: true
}
]
const [tasks, setTasks] = useState(Tasks)
//Após uma ação do usuário...
setTasks(state => {
return state.map((task) => {
if (task.name === "Estudar") {
return (
{
...task,
done: !task.done
}
)
} else {
return {...task}
}
})
})
Alterando uma propriedade utilizando o immer
import produce from "immer"
const Tasks = [
{
name: "Estudar",
done: false
}
{
name: "Jogar videogame",
done: true
}
]
const [tasks, setTasks] = useState(Tasks)
setTasks((state) => return {
produce(state, (draft) => {
const task = draft.find((task) => task.name === "Estudar");
task.done = !task.done;
})
})
Vamos entender o código utilizando o immer. Ele possui uma função chamada produce, que recebê dois parâmetros:
1º Argumento é o valor que estamos querendo alterar. No nosso caso, é o nosso estado que contém o array Tasks.
2º Argumento é uma callback que recebe por convenção um parâmetro chamado draft (rascunho), e ele faz uma cópia do valor do 1º parâmetro.
É nesta cópia que eu realizo, de forma mutável (atualizando, e não substituindo) as alterações no meu estado. Por baixo dos panos, o immer irá transformar esse código mutável em um código imutável, para manter a performance do React.
Espero que esse post tenha contribuido de alguma forma para você. Muito obrigado.
Fique a vontade para acrescentar algo.