E aí, programador! o/
Nessa continuação da aula anterior iremos olhar agora para 2 dicas mais avançadas do useState.
A primeira é que podemos usar uma função para definir o valor inicial do useState:
import { useState } from "react";
function getInitialValue() {
console.log("obtendo valor inicial")
return 1 + 1
}
export default function useCounter() {
const [count, setCount] = useState(getInitialValue())
const increment = () => {
setCount(count + 1)
}
return { count, increment }
}
Mas isso apresenta um problema, como podemos ver no console, que é o fato da função ser executada em cada montagem. Para resolver isso só precisamos envolver a chamada da função em uma função anônima:
Obs.: isso acontece porque, dessa forma, estamos passando a definição de uma função, não o resultado dela, e o useState sabe que precisará executar essa função internamente e apenas na primeira montagem.
Obs².: essa técnica é muito útil quando o nosso estado inicial depende de um cálculo, especialmente um cálculo que “custa caro” em termos computacionais.
import { useState } from "react";
function getInitialValue() {
console.log("obtendo valor inicial")
return 1 + 1
}
export default function useCounter() {
const [count, setCount] = useState(() => getInitialValue())
const increment = () => {
setCount(count + 1)
}
return { count, increment }
}
A segunda dica é relacionada a função de setState. Quando vamos usá-la para definir um novo valor que depende do valor anterior não podemos apenas colocar a expressão diretamente no parâmetro. Podemos ver o problema que isso causa quando chamamos o setState mais de uma vez ao mesmo tempo:
Obs.: repare que o valor só aumenta em 1, não em 2.
import { useState } from "react";
function getInitialValue() {
console.log("obtendo valor inicial")
return 1 + 1
}
export default function useCounter() {
const [count, setCount] = useState(() => getInitialValue())
const increment = () => {
setCount(count + 1)
setCount(count + 1)
}
return { count, increment }
}
Isso ocorre porque em algumas situações, por uma questão de eficiência, o React poderá executar os setState de forma assíncrona. Ele poderá “juntar” as execuções para otimizar sua execução.
A solução para isso é bem fácil. O setState aceita como parâmetro uma função de callback cujo primeiro argumento é o valor “imediatamente” anterior, o que nos permite ter acesso a esse valor sempre atualizado. O retorno desse callback deve ser o valor que queremos “setar” no estado:
import { useState } from "react";
function getInitialValue() {
console.log("obtendo valor inicial")
return 1 + 1
}
export default function useCounter() {
const [count, setCount] = useState(() => getInitialValue())
const increment = () => {
setCount((previousCount) => previousCount + 1)
setCount((previousCount) => previousCount + 1)
}
return { count, increment }
}
Fazendo dessa forma as duas execuções são levadas em consideração corretamente e nosso valor passa a incrementar de 2 em 2.