Contents

Como usar as teclas de reação para evitar conflitos de componentes

A estrutura do React pode apresentar desafios intrincados, levando a comportamentos imprevistos ou defeitos indescritíveis que se mostram difíceis de resolver para aqueles que não compreendem suas causas principais.

Ao renderizar um componente condicionalmente com base em valores de propriedade específicos, pode ocorrer uma anomalia conhecida como bug de “renderização condicional do mesmo componente”. Para aprofundar esse problema e descobrir sua resolução usando as chaves do React, examine o problema de perto.

Componentes do React nem sempre são independentes

A estrutura descomplicada do React é uma razão significativa pela qual é altamente recomendável adquirir proficiência nesta biblioteca JavaScript para construir interfaces de usuário. No entanto, embora existam inúmeros benefícios associados ao uso do React, é importante reconhecer que ele tem seu quinhão de imperfeições e defeitos.

A questão em questão surge da circunstância em que um componente é exibido contingentemente com base em critérios específicos, mas fornecido com atributos diferentes durante sua instanciação.

O React aproveita seu algoritmo de diferenciação de DOM virtual para atualizar com eficiência apenas as partes do DOM real que foram alteradas desde a renderização anterior. Essa estratégia baseia-se na suposição de que a maioria das mudanças ocorre no nível de elementos individuais dentro da hierarquia, e não no nível superior. Conseqüentemente, ao comparar componentes irmãos com marcação idêntica e nenhum estado local, o algoritmo do React os reconhece como equivalentes e pula sua re-renderização. Portanto, qualquer estado definido em um desses componentes persiste em renderizações sucessivas porque eles não são atualizados.

Deixe-me fornecer uma interpretação mais refinada dessa declaração. Suponha que examinamos uma instância da seguinte tabulação de Componentes:

 import { useState, useEffect } from "react"

export function Counter({name}) {
  const [count, setCount] = useState(0)

  return(
    <div>
      <div>{name}</div>
      <button onClick={() => setCount(c => c-1)}> - </button>
      <br />
      <button onClick={() => setCount(c => c \+ 1)}> \+ </button>
    </div>
  )
}

O componente “Counter” recebe uma propriedade nomeada de sua entidade pai por meio de um ato de desconstrução de objeto, que serve como um método para incorporar propriedades dentro do contexto do aplicativo React. O componente subsequentemente exibe essa designação em um elemento HTML div. Além disso, apresenta dois elementos de interface-um projetado para reduzir o valor armazenado no estado e outro para aumentá-lo.

O código acima mencionado, especificamente referente à implementação do aplicativo dentro do componente “App”, foi questionado por seu possível problema. Deve-se observar que não existe mau funcionamento no trecho de código fornecido; em vez disso, está dentro da utilização da variável “counter” dentro do referido componente “App”.

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

export default function App() {
  const [isKingsley, setIsKingsley] = useState(true)

  return(
    <div>
      { isKingsley ? <Counter name="Kingsley"/> : <Counter name="Sally"/> }
      <br/>
      <button onClick={() => setIsKingsley(k => !k)}> Swap </button>
    </div>
  )
}

O código acima mencionado exibe inerentemente a enumeração apelidada de “Kingsley” por padrão. No entanto, se alguém aumentar a contagem do referido contador para um valor de “cinco” e, posteriormente, tocar no dispositivo de tabulação “Trocar”, ele exibirá prontamente uma enumeração alternativa denominada “Sally.

No entanto, o desafio reside no fato de que o contador não retorna ao seu estado inicial de zero depois de reorganizado.

O problema em questão surge devido ao fato de que ambas as instâncias do componente renderizam conjuntos idênticos de elementos em uma sequência específica. No entanto, o React falha em distinguir entre os contadores “Kingsley” e “Sally” por conta de sua propriedade compartilhada, ou seja, o atributo “name”. Lamentavelmente, o React não utiliza essa distinção para identificar diferenças entre componentes com valores de propriedades equivalentes.

Uma solução possível para o problema dos dois contadores sendo exibidos um sobre o outro é modificar a estrutura do Document Object Model (DOM) para criar estruturas de árvore distintas para os dois contadores. Especificamente, pode-se colocar o primeiro contador dentro de um elemento div e o segundo contador dentro de um elemento section. Ao fazer isso, os dois elementos seriam renderizados separadamente, evitando a sobreposição. No entanto, a implementação dessa abordagem exige um entendimento completo do DOM e de suas propriedades.

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

export default function App() {
  const [isKingsley, setIsKingsley] = useState(true)

  return (
    <div>
      { isKingsley ?
         (<div>
          <Counter name="Kingsley"/>
         </div>)
        :
         (<section>
          <Counter name="Sally"/>
         </section>)
      }
      <br />
      <button onClick={() => setIsKingsley(k => !k)}> Swap </button>
    </div>
  )
}

O comportamento do aplicativo muda quando o botão “Kingsley” é clicado e trocado por outro elemento na árvore DOM. Isso resulta em uma redefinição do estado devido à dissimilaridade entre as estruturas das árvores DOM originais e modificadas.

“ ”, onde o mais interno contém um único elemento. Por outro lado, quando o valor “isKingsley” muda entre falso e verdadeiro, a estrutura resultante sofre uma mudança de “ ” para “ ”, que substitui a tag mais interna por uma tag mais externa que engloba tanto o original quanto seus componentes filhos. Essa transformação estrutural solicita que o React recrie o componente Counter

Como alternativa, é possível resolver esse problema sem modificar os componentes estruturais subjacentes do código HTML. Essa abordagem elimina a necessidade de ajustar a formatação para resolver efetivamente o problema em questão.

Usando chaves para renderizar um novo componente

Para que o React distinga entre os componentes durante a renderização, ele depende de chaves. Portanto, ao apresentar componentes idênticos, torna-se necessário atribuir uma chave distinta a cada instância de forma a informar o React de sua individualidade.

Modifique cada contador incluindo uma chave adicional, como segue:

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

export default function App() {
  const [isKingsley, setIsKingsley] = useState(true)

  return(
    <div>
      { isKingsley ?
         <Counter key="Kingsley" name="Kingsley"/> :
         <Counter key="Sally" name="Sally"/>
       }
      <br/>
      <button onClick={() => setIsKingsley(k => !k)}> Swap </button>
    </div>
  )
}

Ao aumentar o valor do contador “Kingsley” e clicar no botão “Swap”, o React gera uma nova instância do contador e restaura seu estado interno para um valor inicial de zero.

Ao renderizar uma matriz que compreende várias instâncias de um tipo de dados uniforme no React, é altamente recomendável empregar chaves exclusivas para distingui-las. Isso ocorre porque o React não tem a capacidade de diferenciar elementos individuais dentro de tais arrays, e atribuir identificadores distintos por meio de chaves garante que cada instância seja reconhecida exclusivamente pela estrutura.

 export default function App() {
  const names = ["Kingsley", "John", "Ahmed"]

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

O React utiliza uma estrutura de dados interna conhecida como “contador” para cada elemento individual dentro de um array ao qual são atribuídas chaves. Isso permite que o sistema detecte e atualize quaisquer modificações feitas no array associado em tempo real.

Outro caso de uso de chave avançada

Você pode utilizar chaves para estabelecer uma relação entre dois elementos distintos com base no valor da variável de estado. Em outras palavras, você pode conectar um componente de entrada com vários componentes que mudam de acordo com a condição da variável de estado.

Para demonstrar, ajuste o componente App:

 import { useState } from "react"

export default function App() {
  const [isKingsley, setIsKingsley] = useState(true)

  return(
    <div>
      { isKingsley ? <div>Kingsley's Score</div> : <div>Sally's score</div> }
      <input key={ isKingsley? "Kingsley" : "Sally" } type="number"/>
      <br/>
      <button onClick={() => setIsKingsley(k => !k)}> Swap </button>
    </div>
  )
}

Sempre que o usuário alternar entre os elementos div associados a Kingsley e Sally clicando no botão, o atributo chave da entrada é modificado automaticamente de “Kingsley” para “Sally” ou vice-versa. Como resultado, o React requer uma reconstrução completa do elemento de entrada a cada pressionamento sucessivo do botão.

Mais dicas para otimizar aplicativos React

A otimização do código é essencial para fornecer uma experiência de usuário agradável em aplicativos da Web e móveis, pois desempenha um papel crítico em garantir que o aplicativo seja executado de maneira suave e eficiente. Familiarizando-se com várias técnicas de otimização, você pode maximizar o desempenho de seus aplicativos baseados em React e aumentar a satisfação geral do usuário.

Aplicativos React Native, como aplicativos da Web, também se beneficiam de várias estratégias de otimização. Uma ampla gama de técnicas de aprimoramento de desempenho pode ser aplicada para melhorar sua funcionalidade e experiência do usuário.