React: Itens de lista com `chave` única são renderizados novamente quando a ordem dos itens muda.

Criado em 15 jul. 2018  ·  3Comentários  ·  Fonte: facebook/react

Você quer solicitar um recurso ou relatar um bug ?
Erro

Qual é o comportamento atual?
Ao renderizar uma lista de itens com key definida como propriedade única em cada elemento de item, se a ordem dos itens mudar em relação à renderização anterior, os elementos de item cujos índices mudaram são renderizados novamente (uma nova instância é criada) em vez de - usando a instância existente (mapeada por meio de chave).

Por exemplo, https://codesandbox.io/s/r5p48kzop
Renderizando uma lista boxes com cada caixa tendo id , top , left & color props. A cada 750ms , atualizamos os valores ( top , left ) de todos os elementos dentro do array boxes .

Durante a atualização, se a ordem dos elementos não mudar, cada caixa será animada em sua nova posição. No entanto, se descomentarmos a linha 31, que embaralha as caixas, então apenas os elementos que mantêm sua posição da renderização anterior são animados para novas posições.

Você pode observar esse comportamento na sandbox. Com _shuffle ativado, às vezes as caixas saltam para suas novas posições, enquanto com _shuffle desativado elas sempre são animadas.

Se o comportamento atual for um bug, forneça as etapas para reproduzir e, se possível, uma demonstração mínima do problema. Cole o link para o seu exemplo JSFiddle (https://jsfiddle.net/Luktwrdm/) ou CodeSandbox (https://codesandbox.io/s/new) abaixo:
https://codesandbox.io/s/r5p48kzop

Qual é o comportamento esperado?
Independentemente da ordem de boxes todos os elementos da caixa devem ser animados em suas novas posições, pois eles têm a propriedade key exclusiva definida neles.

Quais versões do React e quais navegadores / sistemas operacionais são afetados por esse problema?
Reaja 16.3.2 & 16.4.1 , Chrome, MacOS.

Comentários muito úteis

Ei @ dhruvparmar372!

Esta parece ser uma limitação do DOM. Para demonstrar isso, criei este JSFiddle que altera a ordem de dois nós DOM e, em seguida, aplica uma classe para acionar uma transição.

Acontece que você pode contornar esse problema disparando um refluxo entre alterar a ordem e atualizar as propriedades da animação.

Eu adicionei um pouco de código ao seu CodeSandbox para torná-lo visível quando um componente é recriado pelo React, alterando <Box /> para ser um componente de classe e criando um id único no construtor. Como você pode ver, o ID permanecerá consistente: https://codesandbox.io/s/jn42wvl343

Além disso, apliquei a solução alternativa de refluxo ao seu exemplo, dividindo a atualização em dois setState s. O primeiro mudará a ordem, depois acionamos um refluxo e depois mudamos a posição. Isso parece funcionar bem no Chrome, Firefox, Safari e Edge (CodeSandbox não oferece suporte ao IE11, então não pude testar nesse navegador).

Todos 3 comentários

Ei @ dhruvparmar372!

Esta parece ser uma limitação do DOM. Para demonstrar isso, criei este JSFiddle que altera a ordem de dois nós DOM e, em seguida, aplica uma classe para acionar uma transição.

Acontece que você pode contornar esse problema disparando um refluxo entre alterar a ordem e atualizar as propriedades da animação.

Eu adicionei um pouco de código ao seu CodeSandbox para torná-lo visível quando um componente é recriado pelo React, alterando <Box /> para ser um componente de classe e criando um id único no construtor. Como você pode ver, o ID permanecerá consistente: https://codesandbox.io/s/jn42wvl343

Além disso, apliquei a solução alternativa de refluxo ao seu exemplo, dividindo a atualização em dois setState s. O primeiro mudará a ordem, depois acionamos um refluxo e depois mudamos a posição. Isso parece funcionar bem no Chrome, Firefox, Safari e Edge (CodeSandbox não oferece suporte ao IE11, então não pude testar nesse navegador).

hey @ philipp-spiess obrigado por esclarecer o problema e os exemplos para a solução alternativa.

Oi @ philipp-spiess

Eu tenho o mesmo problema com a classificação da lista 😔
Infelizmente, seu exemplo Codesandbox acima não está mais funcionando (

Aqui está um exemplo:
https://jsfiddle.net/9odLvbrx/
Ele classifica os itens no clique com uma transição CSS simples.
O problema é que a transição aparece apenas no item selecionado e omite o restante deles.

Eu sei como contornar o problema (comentado no código), mas funciona bem apenas em listas em que a quantidade de itens nunca muda. Então, se eu quiser adicionar ou remover um item - o material se torna incrivelmente complexo. Como posso usar sua solução de sobrecarga de refluxo para fazer isso acontecer no meu exemplo?

Desde já, obrigado! 😊

Esta página foi útil?
0 / 5 - 0 avaliações