Como você pode convencer o React de que dois usos de um componente precisam de seu próprio estado individual? Com chaves, claro!

A abordagem do React pode ser bastante complicada e você pode encontrar um comportamento inesperado ou até mesmo bugs sutis. Livrar-se de tais bugs pode ser bastante difícil se você não estiver familiarizado com sua causa.

Um bug específico surge quando você renderiza condicionalmente o mesmo componente com propriedades diferentes. Explore este bug em detalhes e descubra como usar as chaves do React para resolvê-lo.

Os componentes do React nem sempre são independentes

Sua sintaxe direta é uma das principais razões você deve aprender Reagir. Mas, apesar de muitas vantagens, a estrutura não é isenta de bugs.

O bug sobre o qual você aprenderá aqui ocorre quando você está renderizando condicionalmente o mesmo componente, mas passando props diferentes.

Em casos como esse, o React assumirá que os dois componentes são iguais, portanto não se preocupará em renderizar o segundo componente. Como resultado, qualquer estado definido no primeiro componente persistirá entre as renderizações.

Para demonstrar, pegue este exemplo. Primeiro, você tem o seguinte Contador componente:

import { useState, useEffect } from"react"

exportfunctionCounter({name}) {
const [count, setCount] = useState(0)

return(


{name}</div>

Esse Contador componente aceita um nome do pai por meio da desestruturação do objeto, que é uma maneira de use adereços no React. Em seguida, ele renderiza o nome em um. Também retorna dois botões: um para decrementar o contar no estado e outro para incrementá-lo.

Tenha em mente que não há nada de errado com o código acima. O bug vem do seguinte bloco de código (o componente App), que usa o contador:

import { useState } from"react"
import { Counter } from"./Counter"

exportdefaultfunctionApp() {
const [isKingsley, setIsKingsley] = useState(true)

return(


{ isKingsley? <Countername="Kingsley" />: <Countername="Sally" /> }


Por padrão, o código acima renderiza o contador chamado Kingsley. Se você aumentar o contador para cinco e clicar no botão Trocar botão, ele renderizará o segundo contador chamado Sally.

Mas o problema é que o contador não será redefinido para seu estado padrão de zero depois que você os trocar.

Esse bug ocorre porque ambos os estados renderizam os mesmos elementos na mesma ordem. O React não sabe que o contador "Kingsley" é diferente do contador "Sally". A única diferença está no nome prop mas, infelizmente, React não usa isso para diferenciar elementos.

Você pode contornar esse problema de duas maneiras. A primeira é alterando seu DOM e tornando as duas árvores diferentes. Isso requer que você entenda o que é o DOM. Por exemplo, você pode agrupar o primeiro contador dentro de um elemento e o segundo dentro de um elemento:

import { useState } from"react"
import { Counter } from"./Counter"

exportdefaultfunctionApp() {
const [isKingsley, setIsKingsley] = useState(true)

return (


{ isKingsley?
(<div>
"Kingsley" />
</div>)
:
(<section>
"Sally" />
</section>)
}


Se você incrementar o contador "Kingsley" e clicar Trocar, o estado é redefinido para 0. Novamente, isso acontece porque a estrutura das duas árvores DOM é diferente.

Quando o isKingsley variável é verdadeiro, a estrutura será div >div > Contador (um div contendo um div, contendo um contador). Quando você troca o estado do contador usando o botão, a estrutura se torna div > seção > Contador. Por causa dessa discrepância, o React renderizará automaticamente um novo Counter com um estado redefinido.

Você pode nem sempre querer alterar a estrutura de sua marcação dessa maneira. A segunda forma de resolver esse bug evita a necessidade de marcação diferente.

Usando chaves para renderizar um novo componente

As chaves permitem que o React diferencie os elementos durante o processo de renderização. Portanto, se você tiver dois elementos exatamente iguais e quiser sinalizar para o React que um é diferente do outro, será necessário definir um atributo de chave exclusivo em cada elemento.

Adicione uma chave para cada contador, assim:

import { useState } from"react"
import { Counter } from"./Counter"

exportdefaultfunctionApp() {
const [isKingsley, setIsKingsley] = useState(true)

return(


{ isKingsley?
"Kingsley" name="Kingsley" />:
"Sally" name="Sally" />
}


Agora, quando você incrementa o contador "Kingsley" e clica Trocar, React renderiza um novo contador e redefine o estado para zero.

Você também deve usar chaves ao renderizar uma matriz de itens do mesmo tipo, pois o React não saberá a diferença entre cada item.

exportdefaultfunctionApp() {
const names = ["Kingsley", "John", "Ahmed"]

return(


{ names.map((name, index) => {
return<Counterkey={index}name={name} />
})}
</div>
)
}

Ao atribuir chaves, o React associará um contador separado a cada item. Dessa forma, ele pode refletir quaisquer alterações feitas na matriz.

Outro caso de uso de chave avançada

Você também pode usar chaves para associar um elemento a outro elemento. Por exemplo, você pode querer associar um elemento de entrada com diferentes elementos dependendo do valor de uma variável de estado.

Para demonstrar, ajuste o componente App:

import { useState } from"react"

exportdefaultfunctionApp() {
const [isKingsley, setIsKingsley] = useState(true)

return(


{ isKingsley? <div>Kingsley's Scorediv>: <div>Sally's scorediv> }
"Kingsley": "Sally" } type="number"/>


Agora, toda vez que você alternar entre os elementos para Kingsley e Sally, você está alterando automaticamente o atributo-chave de sua entrada entre "Kingsley" e "Sally". Isso forçará o React a renderizar completamente o elemento de entrada a cada clique do botão.

Mais dicas para otimizar aplicativos React

A otimização de código é fundamental para criar uma experiência de usuário agradável em seu aplicativo da Web ou móvel. Conhecer diferentes técnicas de otimização pode ajudá-lo a obter o máximo de seus aplicativos React.

A melhor parte é que você também pode aplicar a maioria dessas técnicas de otimização com aplicativos React Native.