React-window: Suporte a conteúdo medido just-in-time

Criado em 30 mai. 2018  ·  132Comentários  ·  Fonte: bvaughn/react-window

Para evitar adicionar custos aos componentes existentes de lista e grade, crie uma nova variante (por exemplo, DynamicSizeList e DynamicSizeGrid ). Essa variante deve medir automaticamente seu conteúdo durante a fase de confirmação.

MVP

A implementação inicial disso pode funcionar de forma semelhante a como CellMeasurer funciona em reativado:

  1. O conteúdo é medido apenas se não houver medições atuais.
  2. As medições precisam ser reiniciadas externamente (imperativamente) se algo mudar.
  3. As células em um determinado índice só podem ser posicionadas depois que todas as células anteriores a esse índice foram medidas.

Meta

Este componente poderia ter um desempenho melhor se removêssemos a terceira restrição acima, permitindo acesso aleatório (por índice de item ou deslocamento de rolagem) sem medir os itens anteriores. Isso tornaria a janela de reação muito mais eficiente para casos de uso como aplicativos de bate-papo.

Isso também desbloquearia a capacidade de usar um ResizeObserver (por meio de medida de reação ) para detectar automaticamente o tamanho do item e remover o cache de posição e medições por completo. Isso eliminaria a necessidade de redefinir imperativamente as medições em cache e melhorar drasticamente a API.

Para que o acima seja possível, os componentes de lista / grade dinâmica precisariam usar uma abordagem drasticamente diferente para mapear o deslocamento para o índice e vice-versa. ( Este comentário sobre "ancoragem de rolagem" em react-virtualized tem alguns visuais interessantes.) Essencialmente, precisaríamos fazer algo assim:

  • Estimar o tamanho total com base no número de itens multiplicado por um estimatedItemSize prop. (Este tamanho estimado não precisa ser ajustado, uma vez que o mapeamento descrito abaixo não é difuso.)

  • Quando a posição de rolagem muda, compare o novo deslocamento com o anterior. Se o delta for maior que algum limite [a ser determinado] , defina o novo deslocamento como a "âncora de rolagem". Mapeie o deslocamento para um índice estimado (por exemplo, divida o deslocamento pelo tamanho rolável total estimado e multiplique pelo número de itens na coleção). Armazene este índice mapeado como o "índice âncora". Por exemplo, se a lista descrita pela imagem abaixo tivesse 250 itens, o "índice âncora" seria 132.

screen shot 2018-06-10 at 11 58 38 am

  • Quando a posição de rolagem muda, se o delta for menor que o limite , escolha quais novos itens renderizar em relação ao índice âncora. Posicione esses itens em relação aos itens posicionados anteriormente. Continuando com o exemplo acima, se a lista foi rolada por uma pequena quantidade (200px), 200px de linhas adicionais precisariam ser anexadas abaixo dos itens posicionados anteriormente:

screen shot 2018-06-10 at 12 01 01 pm

A abordagem acima tem apenas uma grande desvantagem: alinhar os itens corretamente nos limites da lista. Se os índices de itens forem estimados (conforme descrito acima), eles provavelmente não se alinharão exatamente com o início ou o final da área de rolagem.

  • O final pode ser potencialmente contabilizado ajustando o tamanho total estimado conforme o usuário rola mais perto do final (embora isso possa fazer a rolagem parecer irregular).
  • O início da lista é mais difícil de manusear, pois o primeiro item precisa se alinhar com o deslocamento zero, embora ainda pareça se conectar de forma contígua com os itens de algum deslocamento maior que zero. Talvez outro limite possa ser usado, uma "zona segura", perto do início da lista (por exemplo, se o deslocamento da rolagem for menor que algum valor absoluto), o que forçaria a lista a medir todas as células até aquele ponto para que se alinhem corretamente. O custo dessa medição forçada seria relativamente baixo, uma vez que seria apenas um pequeno número de itens.
    screen shot 2018-06-10 at 5 04 42 pm

O único caso que ainda não seria tratado corretamente com a abordagem acima seria uma âncora de rolagem que é definida fora da "zona segura", mas uma rolagem atual que vai para dentro da zona segura (conforme mostrado abaixo). Se o usuário rolar lentamente de volta para o início da lista, pode ser difícil alinhar a primeira célula com zero sem introduzir scroll janky.
screen shot 2018-06-10 at 5 08 26 pm

👋 help wanted

Comentários muito úteis

Não há "vocês" neste projeto. É mantido por uma única pessoa.

E é um pouco imprudente deixar comentários sobre várias questões no mesmo dia reclamando da mesma coisa. Certamente, use apenas o virtualizado de reação.

Todos 132 comentários

Trabalho em andamento para MVP disponível em https://github.com/bvaughn/react-window/compare/master...issues/6

Eu uso isso dentro de mui-downshift e atualmente ainda uso UNSAFE_componentWillReceiveProps , embora planeje tentar portar para react-window em um futuro próximo (assim que a altura do conteúdo dinâmico estiver disponível).

este é um mecanismo reutilizável em UITableView no IOS?

@luoboding Não entendo sua pergunta. Você poderia elaborar?

@bvaughn desculpe, meu amigo, meu inglês não é muito bom.

Eu tenho um problema no meu projeto, eu tenho milhares de opções em select element, ele fica muito lento e emperrado quando a página recarrega, eu tentei escrever um componente para torná-lo melhor, eu era um desenvolvedor IOS, eu conheço um mecanismo reutilizável no UITableView no IOS, se eu precisar de um elemento de seleção de altura de 500px, eu configuro a altura do elemento-opção para 100px, então eu só preciso criar (Math.floor (500/100)) o número do elemento de opção e a capacidade da fila (fila da fonte de dados exibida atualmente ), ao rolar a tela para selecionar o elemento para cima ou para baixo, basta empurrar ou pop na fila para renderizá-lo novamente.

Eu quero importar react-window no meu projeto, funciona como mencionei?

O que você está descrevendo é como a janela de reação (e janelas, ou seleção de oclusão, em geral) funciona. Não está realmente relacionado a esse problema. Trata-se de medir o conteúdo em janelas na hora certa. No seu caso, os objetos têm uma altura fixa - então você pode usar o componente FixedSizeList : https://react-window.now.sh/#/examples/list/fixed -size

É bom ver a ancoragem endereçada nativamente na janela de reação.

A propósito, desculpe se eu levantei a barra um pouco demais nos diagramas ... 😅

@bvaughn quando você lançará este recurso, estou procurando por isso

Publiquei 1.0.0 sem essa funcionalidade porque estou tendo problemas para encontrar tempo (e energia) para terminar isso agora. Ainda pretendo adicioná-lo no futuro. Sem estimativa de quando.

Parece que a "lista de ferro" da Polymer usa uma técnica semelhante à que estou propondo aqui: https://github.com/domenic/infinite-list-study-group/blob/master/studies/Polymer-iron-list.md #virtual -list-sizing

isso seria muito útil para nós, agora parece que temos que manter o CSS em sincronia com a lógica do componente que duplica o cálculo da altura apenas para passá-lo para a lista virtual.

@kevinder você pode compartilhar como está abordando o conteúdo medido just-in-time? desde já, obrigado

@carlosagsmendes não tem certeza se isso vai ajudar, mas aqui está o que estou fazendo quando uso isso para exibir o histórico de bate-papo:

1.) No construtor, crie uma referência para a lista e para o meu componente ChatHistory :

  constructor(props) {
    super(props);
    this.listRef = createRef();
    this.chatHistoryRef = createRef();
    this.listHeight = 0;
  }

Eu então passo os refs para ChatHistory que é responsável por renderizar a lista

2.) Em componentDidMount do componente pai, eu uso o ChatHistory ref para obter a altura do elemento:

componentDidMount() {
    this.listHeight = this.chatHistoryRef.current.offsetHeight;
}

3.) No componente pai, mantenho um array em seu estado com os detalhes da história. Ao adicionar um novo item a essa matriz, eu faço assim:

  // find out how many pixels in height the text is going to use
  const size = getSize({
    text: displayText,
    className: styles.message,
  });

  let { height } = size;
  height += 20; // adds some spacing in pixels between messages
...rest of items needed for the chat history item..add them all to an array and update state

getSize é baseado em https://github.com/schickling/calculate-size, mas eu o modifiquei para aceitar a aceitação de um nome de classe. Essa classe é a mesma usada como o contêiner para exibir as mensagens individuais

Tenho certeza de que existe uma maneira melhor de conseguir isso, mas parece muito rápido e ainda não encontrei nenhum problema

@osdlge : Alguma chance de você ter uma demonstração disso em qualquer lugar que eu possa conferir - como Code Sandbox (ou similar)?

@bvaughn com certeza, extraí as partes relevantes do meu código para https://codesandbox.io/s/5z282z7q1l

Obrigado por compartilhar! 😄

Eu empurrei algum trabalho em andamento para uma abordagem inicial sobre conteúdo medido de forma preguiçosa para um ramo chamado issue / 6

Eu também implantei uma demonstração:
https://react-window-next.now.sh/#/examples/list/dynamic -size

Muito legal.

Ainda estou tentando entender os problemas gerais com a rolagem infinita enquanto analiso a origem do branch / 6 e esta discussão. Portanto, a seguinte pergunta pode não fazer sentido, mas aqui vai, já que eu realmente gostaria de entender isso melhor:

A menção acima a 'âncora de rolagem' está relacionada à ancoragem de rolagem como uma técnica como no artigo vinculado ou a especificação de ancoragem de rolagem CSS ?

desde já, obrigado

É meio que tangencialmente relacionado ao seu primeiro link, mas não ao segundo. É apenas um termo que escolhi para designar o problema porque fazia sentido para mim, não porque está relacionado a qualquer outra especificação ou proposta.

Também publiquei uma versão de pré-lançamento da janela de reação para o NPM como "próximo" (por exemplo, yarn add react-window@next ).

Você pode brincar com isso bifurcando este Code Sandbox:
https://codesandbox.io/s/5x8vlm0o7n

Eu apenas testei. Tentei 10.000 parágrafos e tentei pular para o fim. Foi espasmódico.
Se entendi bem, ele deveria ter medido apenas as linhas estimadas para o final e, portanto, deveria ter saltado instantaneamente para o final. Isso está correto?

Em 12 de outubro de 2018, às 12h53, Brian Vaughn [email protected] escreveu:

Também publiquei uma versão de pré-lançamento de react-window para NPM como "next" (por exemplo, yarn add react-window @ next).

Você pode brincar com isso bifurcando este Code Sandbox:
https://codesandbox.io/s/5x8vlm0o7n https://codesandbox.io/s/5x8vlm0o7n
-
Você está recebendo isto porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub https://github.com/bvaughn/react-window/issues/6#issuecomment-429271555 ou ignore o tópico https://github.com/notifications/unsubscribe-auth/ AOf2h7RmSEyGmyrEdMY6GgyZFjCKlDDFks5ukGafgaJpZM4UTb3P .

Não, o branch inicial que empurrei não implementa o algoritmo
descrito nesta edição. É necessária uma abordagem mais ingênua que exige
medir o conteúdo anterior antes de renderizar o conteúdo posterior.

Desculpe pela confusão!

Na sexta-feira, 12 de outubro de 2018, 18:34, akraines [email protected] escreveu:

Eu apenas testei. Tentei 10.000 parágrafos e tentei pular para o
fim. Foi espasmódico.
Se bem entendi, ele deveria ter medido apenas as linhas estimadas
estar no final e, portanto, deveria ter saltado instantaneamente para o
fim. Isso está correto?

Em 12 de outubro de 2018, às 12h53, Brian Vaughn [email protected] escreveu:

Também publiquei uma versão de pré-lançamento do react-window para NPM como
"próximo" (por exemplo, yarn add react-window @ next).

Você pode brincar com isso bifurcando este Code Sandbox:
https://codesandbox.io/s/5x8vlm0o7n < https://codesandbox.io/s/5x8vlm0o7n

-
Você está recebendo isto porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub <
https://github.com/bvaughn/react-window/issues/6#issuecomment-429271555>,
ou silencie o tópico <
https://github.com/notifications/unsubscribe-auth/AOf2h7RmSEyGmyrEdMY6GgyZFjCKlDDFks5ukGafgaJpZM4UTb3P
.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/bvaughn/react-window/issues/6#issuecomment-429282228 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AABznR5R1N0ErukleIfvaLQORF_NECgRks5ukHBHgaJpZM4UTb3P
.

Ei,
Queria perguntar se existe uma estimativa para um lançamento oficial?

Minha equipe usa react-virtualized para um novo projeto que iniciamos, entretanto, precisamos da funcionalidade de rolar para cima e pular para um índice de linha específico (como você pode assumir que nossas linhas têm conteúdo dinâmico, contendo imagens e outros conteúdos variáveis).

Você recomendaria migrar para react-window em sua versão alfa? Ou devemos esperar por um lançamento oficial?

Além disso, se houver alguma maneira de contribuir para a conclusão desse recurso, eu adoraria ajudar 😄

Infelizmente, não posso me comprometer com um cronograma de lançamento no momento porque não fiz muitos testes e não sei que tipo de problemas encontrarei quando fizer isso (ou quanto tempo levará para consertar eles).

Se você gostaria de contribuir, uma maneira seria testar a versão alpha e me informar se ela funciona bem e se você encontrar algum bug.

Provavelmente estarei me concentrando mais nisso em breve, mas não posso dizer quando. Especialmente nas próximas duas semanas, estou distraído pelo React conf e preparando a versão 16.6.

@bvaughn ótimo trabalho 👏 Finalmente, tenha algum tempo para brincar. 🕹

Parece que precisamos de alguns ajustes para ocultar a lista com display: none Por exemplo, você tem uma página com duas guias e deseja alternar entre elas sem perder seu estado atual (posição de rolagem etc.), mas não é um caso de uso raro .

Sandbox de código simples apresentando o problema:
https://codesandbox.io/s/p7vq18wmjq

Está acontecendo porque quando acionamos o display none, todos os filhos terão offsetHeight === 0
resize observa os kiks e atualiza os novos valores. react-window não deve se preocupar com essas situações se o chamador decidir escondê-lo, o basic deve lidar com isso bloqueando handleNewMeasurements

se esta linha
https://github.com/bvaughn/react-window/blob/issues/6/src/DynamicSizeList.js#L443
mudaria para

handleNewMeasurements: instance._handleNewMeasurements

então podemos substituir a lógica padrão

let _handleNewMeasurements

<DynamicSizeList  
  ref={current => {
    if (current) {
      _handleNewMeasurements = current._handleNewMeasurements
      current._handleNewMeasurements = (...args) => {
        if (!isHidden) {
          return _handleNewMeasurements(...args)
        }
      }
    }
  }}
  {...otherProps}

Eu empurrei uma atualização para este branch (e publiquei uma nova tag @next para NPM) que corrige o bug de rolagem suave do Firefox usando margin-top para contabilizar os itens redimensionados enquanto a rolagem está em andamento. É mais complicado do que eu gostaria, mas não conheço melhor maneira de lidar com isso no momento. (Também preciso fazer mais alguns testes dessa abordagem, porque acho que ela pode ter algumas arestas ainda em casos extremos.)

Agradeço o feedback acima, @piecyk. Ainda não tive tempo de me aprofundar nisso. (Este ainda é apenas um projeto paralelo para mim no momento).

Parece que posso remover o hack de margem em favor de scrollBy pelo menos para o Firefox . Porém, precisa testar o IE e o Edge primeiro. Eles podem ter seus próprios desafios.

Sim @bvaughn eu sei, trabalho incrível 👏 Não sei como você encontra tempo! 🥇Kudos para você!

Mas vamos voltar ao problema quando a lista está em algum elemento DOM que está oculto com display none, básico, precisamos verificar se o wrapper tem altura, largura, se não, não queremos iniciar a renderização (atual ele tentará renderizar lista inteira) Vou tentar consertar amanhã (tenho algo escondido)

Sim. Eu entendo o cerne do problema que você está descrevendo. Eu não gosto da ideia de hackear isso substituindo / monkey-patching mais métodos de instância, então eu gostaria de pensar um pouco mais primeiro.

Parece que o pacote @next está quebrado?

https://codesandbox.io/s/5x8vlm0o7n

Não sei se esse é o lugar adequado para deixar uma pergunta, então me desculpe se eu estiver errado. Então, resumindo:

  • Usei DynamicSizeList junto com AutoResizer e, em geral, funciona muito bem. Kudos!
  • Fui solicitado a apresentar linhas cujo conteúdo pode ser expandido (adicionando um div extra com informações suplementares) e retraído.
  • Eu também adicionei (via redux) um suporte nessas linhas que escuta as ações globais de expansão / retração.
  • Coisas divertidas começam. Clico em expandir / retrair e tudo parece ótimo!
  • Se eu rolar um pouco e, em seguida, expandir / retrair todas as linhas, o número de linhas retraídas é o mesmo que o das linhas expandidas. Se eu expandir a retração novamente, o número vai para a metade e assim por diante.
    (ou seja, 30 linhas retraídas -> 10 expandidas -> clique em retrair -> 10 linhas retraídas -> clique em expandir -> 3 linhas expandidas -> clique em retrair -> 3 linhas retraídas).

Tentei recarregar o itemData fornecendo um objeto diferente, mas igual ao hack JSON.parse (JSON.stringify (data)). Sem sorte :-(

Eu suspeito de um erro de cálculo da altura. Alguma ideia para superar esse problema?

Você poderia compartilhar um exemplo de codesandbox? Eu preciso fazer algo semelhante para que possamos nos ajudar

@vtripolitakis Acabei de encontrar um exemplo com linhas expansíveis . Aqui está o link para a discussão

@carlosagsmendes obrigado por isso, mas meu estudo de caso é um pouco diferente, pois eu uso o DynamicSizeList :-(

Então, descobri o motivo do problema:
state.scrollOffset estava assumindo valores negativos.

em src/DynamicSizeList.js , precisamos adicionar o seguinte código na linha 299

if (sizeDeltaForStateUpdate < 0) {
          sizeDeltaForStateUpdate = 0;
        }

Hm ... Eu não esperaria que essa correção estivesse certa, à primeira vista. Um delta de tamanho pode ser legitimamente negativo, não?

Talvez devêssemos ter um guarda ( Math.max(0, prevState.scrollOffset + sizeDeltaForStateUpdate) ) em torno de onde o state.scrollOffset é atualizado?

Olá, enquanto eu depurava meu caso, sizeDeltaTotal assumiu valores negativos e, consequentemente, tornou sizeDeltaForStateUpdate negativo, resultando em um state.scrollOffset negativo após a atualização de estado.

Isso aconteceu quando eu expandi e retrai itens e, em seguida, rolei para o topo tendo scrollOffset 0 e direção backwards . Então, se eu expandir e retrair algumas vezes, recebo os negativos.
Sim, sua sugestão deve ser igualmente boa. ~ Testando agora. ~ Funciona corretamente.

@marcneander, experimente a versão 1.4.0-alpha.1

Sobre ignorar eventos de redimensionamento quando a lista está oculta, talvez algo como https://github.com/piecyk/react-window/commit/acfd88822156611cfd38872acdafbbefd2d0f78f
@bvaughn o que você acha?

Estou tentando adicionar rolagem automática em um aplicativo estilo chatbox e estou tendo este problema: DynamicSizeList does not support scrolling to items that have not yet measured. scrollToItem() was called with index 111 but the last measured item was 110.

Estou tentando chamar scrollToItem(items.length-1) em componentDidUpdate

Este é o comportamento pretendido?

Sim, talvez algo assim funcione @piecyk 👍

Este é o comportamento pretendido?

Não parece @xaviergmail , não. Talvez um bug.

Ei @bvaughn , não é minha implementação de array esparsa bem feita dos componentes internos do Flex 4 DataGrid que pode ajudar aqui. Eu sei que o Flash é: -1 :, mas a última versão do Flex na verdade tinha um excelente mecanismo de layout virtualizado ... porque o Flash :-)

O LinearLayoutVector é uma matriz esparsa para mapeamento entre índices de item e posições de pixel em uma única dimensão. As três operações básicas são:

interface LinearLayoutVector {
   start: (index) => position;
     end: (index) => position;
  indexOf: (position) => index;
}

Internamente, ele aloca baldes em potências de 2 para armazenar posições de itens (a potência específica pode ser ajustada para acomodar melhor tamanhos de itens maiores ou menores). Isso permite pesquisas O (1) index -> position em tempo constante e uma varredura de bloco linear eficiente para pesquisas position -> index . Ele oferece suporte a preenchimento, lacunas, tamanhos padrão e inserção, remoção e atualizações de acesso aleatório.

Eu o transformei para JS cerca de 6 anos atrás, quando estava fazendo várias interfaces de usuário virtualizadas para dispositivos móveis. Ele poderia usar uma atualização para ES6 para facilitar a leitura e provavelmente poderia obter mais velocidade alternando para matrizes digitadas, mas a lógica básica é boa.

Enviei um rascunho de PR para a virtualização de reação algumas semanas atrás, que trocou os componentes internos de CellSizeAndPositionManager com o LLV e resolveu algumas coisas de invalidação de perf / cache. Se você estiver desanimado, ficaria feliz em enviar um PR semelhante para react-window nas próximas semanas.

Olá @trxcllnt 👋

Se você estiver interessado em compartilhar um PR, ficarei feliz em dar uma olhada. Você gostaria de fazer isso contra a ramificação issues/6 (WIP PR # 102).

À primeira vista, linear-layout-vector não parece ter sido testado ou usado demais, então eu teria um pouco de relutância inicial, mas ainda estaria disposto a dar uma olhada. Eu também gostaria de ver quanto peso ele adiciona a um pacote depois de ser feio + reduzido, mas eu não esperaria que ele adicionasse muito. 😄

@bvaughn sem suor, eu entendo

Depois que comentei, lembrei que tinha a demo para a qual fiz a porta: https://github.com/trxcllnt/virt-list. Acesse o site das páginas do GH e jogue a lista de filmes à esquerda e à direita (isso estava relacionado a algumas discussões sobre o desempenho de renderização que estávamos tendo na equipe do iOS na Netflix).

@bvaughn Obrigado por todo o trabalho realizado no ramo de edições / 6 no ano passado!
No momento, estou testando ^1.6.0-alpha.1 e planejo enviar para produção com essa versão.

Pensei em postar o que eu precisava fazer para trabalhar com o novo DynamicSizeList para qualquer pessoa que esteja olhando para este problema e usando o mais recente no branch.

Seguir os documentos vinculados acima e aqueles gerados a partir do ramo de questões / 6 levará a

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

e então a solução foi imitar o que você faz nos testes e ...

import { DynamicSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';

// in constructor(props) for handling scrolling
this.listRef = React.createRef();

// in render()
const allItems = [...];
const Renderer = ({ forwardedRef, style, index, ...rest }) => (
  <div ref={forwardedRef} style={style}>
    <MyCoolComponent index={index} otherProps={otherPropsBasedOnAllItems} />
  </div>
);

const RefForwarder = React.forwardRef((props, ref) => (
  <Renderer forwardedRef={ref} {...props} />
));

return <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
  <div style={{ flexGrow: 0, flexShrink: 0, width: '100%', position: 'sticky', top: 0, zIndex: zIndexHideLayers }}>
    <MyCoolComponentThatControlsScrolling listRef={this.listRef} />
  </div>
  <div style={{ flex: 1, width: '100%' }}>
    <AutoSizer>
      {({ height, width }) => (
        <List ref={this.listRef} itemCount={allItems.length} width={width} height={height}>
          {RefForwarder}
        </List>
      )}
    </AutoSizer>
  </div>
</div>;

Meu exemplo provavelmente inclui mais do que você deseja na página de documentos, mas espero que torne a atualização de documentos mais fácil para você

Feedback sobre a versão atual do ramo?
💯 funciona bem
🎉 obrigado novamente por todo o trabalho!

editar: DynamicSizeList realmente torna esta biblioteca tão fácil de usar agora.

Obrigado por compartilhar os detalhes! Quando eu conseguir alguma largura de banda para resolver esse problema, irei examiná-los.

Acho que essa abordagem pode ser usada junto com a proposta original nesta edição.

Em vez de usar o tamanho anterior do item, poderíamos apenas usar os tamanhos estimados - e refinar com os tamanhos reais conforme alguém rola. (Não acho que haja uma distinção importante entre "tamanho medido anteriormente" e "tamanho estimado", exceto pelo fato de que o tamanho medido anteriormente é provavelmente mais preciso. Ainda assim, isso pode ser uma troca aceitável, pois permitiria para saltarmos para lugares arbitrários nos dados sem renderizar coisas que vieram antes, _e_ isso nos livraria de ter que manter um cache de tamanho de item.)

Acho que isso poderia simplificar significativamente o problema de ancoragem de rolagem. Poderíamos apenas dar o salto inicial (conforme descrito) e então fingir que tudo "antes" (acima ou à esquerda) era exatamente o tamanho estimado. Então, à medida que avançamos, refine.

Talvez funcione?

@bvaughn Isso corrigirá o problema que o @xaviergmail abordou, com a rolagem inicial para "parte inferior" como um bate-papo? Criei uma caixa de códigos e um exemplo de que não está funcionando. Se não, existem soluções alternativas?

https://codesandbox.io/s/vr648ywy3

Vamos manter os comentários sobre esse problema focados na discussão da API, não na solução de problemas.

Eu sugiro Stack Overflow para fazer perguntas.

É possível expor o resetAfterIndex nesta API? Eu adiciono, edito e removo da minha DynamicSizeList e, pelo menos pelo que eu posso deduzir, este seria o método para chamar para consertar alturas, sim?

@bvaughn estava brincando no fim de semana com a ideia de posicionar os itens com o índice âncora e rolar a lista para alinhar o que o usuário está vendo ... Primeiras impressões de que poderia funcionar 😅 Para simplificar, a lista é renderizada sem quaisquer elementos de overscan, também nós precisa mudar como o cache está funcionando (neste wip ele é limpo sempre) ... O que você acha?

implementação poc https://github.com/piecyk/react-window/pull/2/files
aqui está a sandbox do código executando a construção do branch
https://codesandbox.io/s/4x1q1n6nn9

uh-oh o firefox não consegue acompanhar a renderização ao rolar rápido como o Chrome faz com esta abordagem

Estou tentando adicionar rolagem automática em um aplicativo estilo chatbox e estou tendo este problema: DynamicSizeList does not support scrolling to items that have not yet measured. scrollToItem() was called with index 111 but the last measured item was 110.

Estou tentando chamar scrollToItem(items.length-1) em componentDidUpdate

Este é o comportamento pretendido?

Um pouco tarde, mas estou tentando resolver esse problema com este gancho de reação.

Não é a melhor solução, mas ainda estou trabalhando nisso. Talvez possamos trabalhar para torná-lo mais genérico (e simples) e criar um pacote?

Gif para mostrar como isso está funcionando agora:
https://cl.ly/87ca5ac94deb

Talvez possamos abrir uma nova edição para falar sobre uma solução para esse comportamento tipo chat?

uh-oh, o firefox não consegue acompanhar a renderização ao rolar rápido como o Chrome faz com esta abordagem

Parece que funciona no Firefox Nightly versão 68.

@bvaughn Estou usando o DynamicSizeList com os componentes InfiniteLoader e Autosizer para tentar criar um feed. Eu gosto do que vi até agora, continue assim :)

Em termos de API e comportamento:

  1. Podemos obter o objeto de dados como um segundo argumento no retorno de chamada itemKey, do jeito que está em FixedSizeList?

  2. Podemos redefinir a altura do contêiner interno quando o objeto de dados é filtrado / modificado.

Estou usando DynamicSizeList de 1.6.0-alpha.1 com InfiniteLoader por um tempo e tem funcionado muito bem. Obrigado pelo recurso incrível!

No entanto, agora tenho um requisito para usar scrollToItem() . Semelhante a um comentário acima, mas distinto porque nada foi medido ainda, eu obtenho:

DynamicSizeList does not support scrolling to items that yave not yet measured. scrollToItem() was called with index 9 but the last measured item was -1.

Não parece estar relacionado ao tempo, pois tentei chamá-lo depois de um longo setTimeout . Então, posso forçar uma medição? Ou existem soluções alternativas?

EDIT : Deixa initialScrollOffset fez o que eu precisava.

por que usar findDOMNode?

Existem definições de tipo para o branch @next ?

@WillSquire não, eles não @next no DefinitelyTyped (posso estar enganado). Além disso, acho que seria melhor esperar até que este branch seja finalmente fundido e uma nova versão lançada, já que a API ainda pode mudar.

@bvaughn Estou disposto a usar isso no devhub , mas antes de investir na integração, você acha que já está em boa forma ou ainda tem alguns problemas com bloqueadores?

@brunolemos Minha lista de tarefas no nº 102 é bastante precisa, eu acho. Se você testou e acha que ele está em uma boa forma para os navegadores que deseja, mantenha-me informado!

mantenha-me informado!

~ Tentei usar, mas não tive sucesso até agora. ~

Funcionou, mas o desempenho não é bom. Talvez meus itens renderizados sejam caros ou outra coisa.

https://github.com/devhubapp/devhub/pull/152

Parece que algo pode ter quebrado na versão mais recente ao usar o AutoSizer com uma altura de contêiner de 100%

Edit: Consegui encontrar uma solução alternativa usando 100vh e calc ()

algo pode ter quebrado

Muito vago para ser acionável. Compartilhar uma reprodução junto com o comportamento esperado?

Estou usando DynamicSizeList de 1.6.0-alpha.1 com filtros diferentes e alguns modos de exibição de cartão complexos. Mas precisamos acertar com a altura e a largura. Está funcionando bem pra mim.

Obrigado pessoal

Olá, estou testando DynamicSizeList , mas todos os meus itens são renderizados um em cima do outro. Eu passo o atributo de estilo para o item renderizado, mas se logar style , vejo que height é indefinido para cada item, top e left são sempre 0 .
O que eu perdi aqui :-)?

@ graphee-gabriel você perdeu um exemplo de reprodução.

A altura não é especificada intencionalmente inicialmente, a fim de permitir que os itens sejam renderizados com seu tamanho natural ...

Ok, eu entendo a lógica, então esse não é o motivo pelo qual os itens são renderizados uns sobre os outros.
Vou fornecer o máximo de dados possível, pensei que talvez tenha cometido um erro comum ou esquecido uma etapa óbvia que leva a esse problema (como não transmitir o objeto de estilo).

Screen Shot 2019-07-07 at 18 08 53

import React from 'react'
import { DynamicSizeList as List } from 'react-window'

import Layout from '../Layout'
import Text from '../Text'
import withScreenDimensions from '../withScreenDimensions'

class ListView extends React.Component {
  state = {
    availableHeight: 0
  }

  componentDidMount() {
    const checkForHeightChange = () => {
      if (this.containerDiv) {
        const { offsetHeight } = this.containerDiv
        if (this.offsetHeight !== offsetHeight) {
          this.offsetHeight = offsetHeight
          this.setState({ availableHeight: offsetHeight })
        }
      }
    }
    checkForHeightChange()
    this.intervalId = setInterval(checkForHeightChange, 10)
  }

  componentWillUnmount() {
    clearInterval(this.intervalId)
  }

  render() {
    const {
      data,
      renderItem,
      emptyText,
      dimensions,
    } = this.props
    const { width } = dimensions
    const { availableHeight } = this.state
    return (
      <Layout
        centerVertical
        style={{
          height: '100%',
        }}>
        {data && data.length > 0 ? (
          <div
            style={{
              display: 'flex',
              flex: 1,
              height: '100%',
              backgroundColor: 'red',
              alignItems: 'stretch',
              justifyContent: 'stretch',
            }}
            ref={ref => this.containerDiv = ref}
          >
            <List
              height={availableHeight}
              itemCount={data.length}
              width={width > 800 ? 800 : width}
            >
              {({ index, style }) => {
                console.log('style', style)
                return (
                  <div style={style}>
                    {renderItem({
                      item: data[index], index
                    })}
                  </div>
                )
              }}
            </List>
          </div>
        ) : (
            <Text bold center padding accent>{emptyText}</Text>
          )}
      </Layout>
    )
  }
}


export default withScreenDimensions(ListView)

Compartilhar uma sandbox de código onde posso ver isso?

Eu sugeriria _não_ usar uma função embutida para seu representante de item porque ela causa remontagens desnecessárias devido ao fato de que muda cada vez que o pai é processado. (É por isso que todos os exemplos evitam funções embutidas.)

@ graphee-gabriel Eu também tive isso, a documentação não menciona, mas você precisa fazer com que seu componente de linha suporte o recebimento de um ref:

Row = React.forwardRef(
      (row, ref) => (
        <div ref={ref} style={row.style}>
          {renderItem({
            item: data[row.index],
            index: row.index,
          })}
        </div>
      ),
    )

Olá, aqui está:

https://codesandbox.io/s/sweet-sea-irxl8?fontsize=14

Sim, de fato, para as funções inline, é um código muito antigo que tentei migrar para o react-window e não perdi tempo para melhorá-lo aqui também.
Obrigado pelo seu feedback! Deixe-me saber o que você encontrar nesta caixa de areia.

Annnnnd eu deveria ter verificado a mensagem @brunolemos antes de fazer aquele sandbox hehe
Essa era a etapa que faltava e corrigiu meu problema, obrigado!

Isso levantou outro problema, atualizei a caixa de areia para que você possa reproduzir @bvaughn
Encontre aqui: https://codesandbox.io/s/sweet-sea-irxl8

Agora a lista funciona bem, mas estranhamente parece aumentar com o conteúdo e nunca mais encolher novamente.

Significado:

  1. Se eu mostrar 6 itens, vá até o final, está tudo bem.
  2. Mude o conteúdo para mostrar 20 itens, vá até o final, tudo bem.
  3. Volte o conteúdo para 6 itens, role até o último item, mas posso continuar rolando no espaço em branco que parece ter sobrado do conteúdo anterior (o conjunto de dados de 20 itens).

Isso levantou outro problema, atualizei a caixa de areia para que você possa reproduzir @bvaughn
Encontre aqui: https://codesandbox.io/s/sweet-sea-irxl8

Agora a lista funciona bem, mas estranhamente parece aumentar com o conteúdo e nunca mais encolher novamente.

Significado:

  1. Se eu mostrar 6 itens, vá até o final, está tudo bem.
  2. Mude o conteúdo para mostrar 20 itens, vá até o final, tudo bem.
  3. Volte o conteúdo para 6 itens, role até o último item, mas posso continuar rolando no espaço em branco que parece ter sobrado do conteúdo anterior (o conjunto de dados de 20 itens).

Estou tendo o mesmo problema

Isso é exatamente o que eu precisava.
Acabei de testar o DynamicSizeList de 1.6.0-alpha.1 em combinação com o react-virtualized-auto-sizer e o react-window-infinite-loader com resultados muito bons.
Posso ajudar em alguma coisa para avançar?

Olá @bvaughn , você teve tempo de verificar o codesandbox em https://github.com/bvaughn/react-window/issues/6#issuecomment -509213284?

Olá, estou usando DynamicSizeList para meu aplicativo de bate-papo.
Obrigado pelo recurso incrível.

No entanto, tenho problemas com baixo desempenho e muito processamento de script.
Ao rolar, a CPU sempre aumenta e geralmente atinge 100%.
Você tem alguma ideia para soluções?

import { useChatList } from '../../../hooks/chat/useChatList';
import LoadingSpinner from '../../../utils/LoadingSpinner';

import dynamic from 'next/dynamic';
import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
// @ts-ignore
import { DynamicSizeList as List } from 'react-window';
import { Message } from 'src/app/typings';

const { useRef, useCallback } = React;

const RowItem = React.memo(
  ({ forwardedRef, style, index, data }: any) => {
    const item = data[index] as Message;
    if (item) {
      return (
        <div id={item.messageId} ref={forwardedRef} style={style}>
          {item.text && item.text.plainText}
        </div>
      );
    }
    return null;
  },
  (prevProps, newProps) => {
    const { index, data } = prevProps;
    const { index: newIndex, data: newData } = newProps;
    let isMemo = true;
    isMemo = isMemo && index === newIndex;
    isMemo = isMemo && data.length === newData.length;
    return isMemo;
  }
);

function ChatList() {
  const listRef = useRef<HTMLInputElement>();

  const { formatMessages: messages, isLoadingMessages } = useChatList();

  const keyCreator = useCallback((index: number) => `ChatList/RowItem/${messages[index].messageId}`, [messages]);

  if (isLoadingMessages && (!messages || messages.length <= 0)) {
    return <LoadingSpinner />;
  }
  return (
    <div style={{ flex: 1, height: '100%', width: '100%' }}>
      <AutoSizer>
        {({ height, width }) => (
          <List
            ref={(lref: HTMLInputElement) => {
              if (lref !== null) {
                listRef.current = lref;
              }
            }}
            itemCount={messages.length}
            itemData={messages}
            itemKey={keyCreator}
            height={height}
            width={width}
            overscanCount={10}
          >
            {React.forwardRef((props, ref) => (
              <RowItem forwardedRef={ref} {...props} />
            ))}
          </List>
        )}
      </AutoSizer>
    </div>
  );
}

export default ChatList;

スクリーンショット 2019-07-14 11 49 54

Olá @bvaughn , bom trabalho!
Qual é a maneira correta de recalcular as alturas dos itens no redimensionamento do local de trabalho? Com a ajuda dos comentários acima, estou fazendo uma demonstração https://codesandbox.io/s/angry-hill-tcy2m
Quando a largura do local de trabalho muda com o mouse, preciso recalcular a altura de todos os itens (e posso limpar o cache de altura interna do componente VariableSizeList) ...

Existe alguma solução agora para a lista dinâmica? Passei 4 horas tentando fazê-la funcionar, hein?
depois de ler todos os comentários, terminei 😠
Se vocês têm alguma solução de trabalho, por favor me forneça

Não há "vocês" neste projeto. É mantido por uma única pessoa.

E é um pouco imprudente deixar comentários sobre várias questões no mesmo dia reclamando da mesma coisa. Certamente, use apenas o virtualizado de reação.

Eu realmente sinto muito por deixar um comentário como este Brian. Eu descobri esse problema mais tarde, li todos os comentários e pensei que outros estão ajudando você, pelo menos

@ShivamJoker Eu quase fiz funcionar, a única coisa que resta para que funcione perfeitamente é a altura total que continua crescendo, mas nunca diminui depois de alterar o conteúdo para menos itens. Se isso for resolvido, no meu caso de uso parecerá funcionar perfeitamente.

@bvaughn , você teria tempo para verificar o exemplo na caixa de areia de https://github.com/bvaughn/react-window/issues/6#issuecomment -509213284?

=> https://codesandbox.io/s/sweet-sea-irxl8

Começa com a lista mais curta, portanto:

  • role para baixo até o final da lista
  • role para cima e clique em Show Long List
  • role para baixo até o fim
  • role para cima e clique em Show Short List
  • Finalmente, role para baixo uma última vez para ver que a lista curta agora é seguida por muitos espaços em branco.

Obrigada!

@ShivamJoker Eu quase fiz funcionar, a única coisa que resta para que funcione perfeitamente é a altura total que continua crescendo, mas nunca diminui depois de alterar o conteúdo para menos itens. Se isso for resolvido, no meu caso de uso parecerá funcionar perfeitamente.

@bvaughn , você teria tempo para verificar o exemplo na caixa de areia de # 6 (comentário) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

Começa com a lista mais curta, portanto:

  • role para baixo até o final da lista
  • role para cima e clique em Show Long List
  • role para baixo até o fim
  • role para cima e clique em Show Short List
  • Finalmente, role para baixo uma última vez para ver que a lista curta agora é seguida por muitos espaços em branco.

Obrigada!

Sim, basicamente o contêiner interno deve redefinir sua altura ao filtrar / alterar os dados.

@ShivamJoker Eu quase fiz funcionar, a única coisa que resta para que funcione perfeitamente é a altura total que continua crescendo, mas nunca diminui depois de alterar o conteúdo para menos itens. Se isso for resolvido, no meu caso de uso parecerá funcionar perfeitamente.

@bvaughn , você teria tempo para verificar o exemplo na caixa de areia de # 6 (comentário) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

Começa com a lista mais curta, portanto:

  • role para baixo até o final da lista
  • role para cima e clique em Show Long List
  • role para baixo até o fim
  • role para cima e clique em Show Short List
  • Finalmente, role para baixo uma última vez para ver que a lista curta agora é seguida por muitos espaços em branco.

Obrigada!

obrigado, implementei o mesmo esperando que funcione bem para outros usuários também
e sim, eu também vi que o problema de altura com rolagem

@ graphee-gabriel mas também estou tendo mais um problema que minha barra de aplicativos costumava esconder ao rolar para baixo, o que não está acontecendo agora, qual pode ser a solução?
image

Dia bom. Usei DinamycSizeList em meu projeto de demonstração. Tudo estava bem, mas depois de um tempo percebi que o componente da lista começou a funcionar incorretamente. A princípio pensei que fosse alguma biblioteca da qual dependesse a janela de reação. Mas olhando para a sua demonstração
https://react-window-next.now.sh/#/examples/list/dynamic -size
notou quase o mesmo resultado, embora no passado também tenha funcionado perfeitamente. Você poderia sugerir a causa desses bugs?

@simeonoff

Sim, basicamente o contêiner interno deve redefinir sua altura ao filtrar / alterar os dados.

como devo fazer isso eu tentei colocar uma altura de estado, mas não parece funcionar
qualquer solução ?

@simeonoff

Sim, basicamente o contêiner interno deve redefinir sua altura ao filtrar / alterar os dados.

como devo fazer isso eu tentei colocar uma altura de estado, mas não parece funcionar
qualquer solução ?

Deve ser implementado internamente pela biblioteca.

@ShivamJoker Eu quase fiz funcionar, a única coisa que resta para que funcione perfeitamente é a altura total que continua crescendo, mas nunca diminui depois de alterar o conteúdo para menos itens. Se isso for resolvido, no meu caso de uso parecerá funcionar perfeitamente.

@bvaughn , você teria tempo para verificar o exemplo na caixa de areia de # 6 (comentário) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

Começa com a lista mais curta, portanto:

  • role para baixo até o final da lista
  • role para cima e clique em Show Long List
  • role para baixo até o fim
  • role para cima e clique em Show Short List
  • Finalmente, role para baixo uma última vez para ver que a lista curta agora é seguida por muitos espaços em branco.

Obrigada!

Você pode definir a chave para evitar espaços em branco.
https://codesandbox.io/s/blissful-voice-mzjsc

Olá @bvaughn obrigado por este projeto incrível!

Por necessidade, tenho gasto bastante tempo no código DynamicLists tentando descobrir como rolar para qualquer lugar sem quaisquer limitações e como rolar para qualquer item, medido ou não.

Consegui fazer isso aqui https://github.com/bvaughn/react-window/compare/issues/6...Sauco82 : issues / 6 livrando-me de lastMeasuredIndex e verificando por item em vez de itemIsMeasured , o que obviamente requer muitas outras mudanças.

Nunca participei de um projeto de código aberto nem usei o Flow, então não tenho certeza se isso é útil ou vale a pena incluir, nem se devo tentar diretamente um PR ou discuti-lo aqui.

Estou feliz em ajudar e ajustar, então se você precisar de alguma coisa, por favor me avise

Ei, aqui está uma solução muito mais simples (não há necessidade de anexar elementos fantasmas ao DOM para calcular seu tamanho):
Codesandbox

Ei, aqui está uma solução muito mais simples (não há necessidade de anexar elementos fantasmas ao DOM para calcular seu tamanho):
Codesandbox

Impressionante! Funciona para mim. Bom trabalho.

@Kashkovsky calculou o tamanho se fosse atualizado
e itemSize chama uma vez

@ userbq201 @Kashkovsky ótima solução alternativa! De alguma forma, no meu caso não funcionou imediatamente, tive que modificar o código de ChatHistory.js assim:

    const listRef = useRef(); // added
    const sizeMap = useRef({});
    const setSize = useCallback((index, size) => {
        sizeMap.current = {...sizeMap.current, [index]: size};
        listRef.current.resetAfterIndex(index); // added
    }, []);
    const getSize = useCallback(index => sizeMap.current[index] || 60, []);
    // ...
    <List ref={listRef}

Caso contrário, todos os itens são renderizados com a mesma altura padrão. No seu caso funciona como está, não consigo explicar por que há uma diferença ... talvez @bvaughn possa.

@bvaughn e se tivermos que ativar um comportamento semelhante para SSR? alguma dica para esse lado?

@bvaughn Sou eu ou sua demonstração não está funcionando?

Boa implementação @Kashkovsky @ kirill-konshin e @ userbq201 !

Como você abordaria o uso de memoização com esta solução?

Tentei empacotar ChatMessage em memo com areEqual , mas o React ainda renderiza novamente cada objeto toda vez que uma mensagem é adicionada à lista.

Em minhas outras FixedSizedLists, a memoização funciona bem com esse wrapper memo / areEqual, mas talvez o ref={root} esteja afetando isso?

Você pode saber facilmente se o React está renderizando novamente os componentes colando um

Eu criei o exemplo aqui: https://codesandbox.io/s/dynamic-size-of-react-window-list-items-nb038


EDIT: Corrigi o memoization - destina-se a embrulhar o componente funcional inicial com memo - não o como eu tinha feito. Aqui está uma solução memoized caso alguém tenha uma estrutura DOM complexa dentro de suas listas (ou se eles tiverem que mapear vídeos como eu): https://codesandbox.io/s/dynamic-size-of-react-window-list -items-errt4


EDIT 2: Acontece que a renderização inicial das linhas está completamente bem, mas chamar resetAfterIndex é muito difícil de gerenciar. Meus dados mudam (por exemplo, quando o usuário seleciona uma conversa diferente). Mas o verdadeiro problema é que resetAfterIndex parece funcionar antes que o novo setSize possa terminar. Assim, ele limpa com sucesso o estilo em cache, mas então apenas gera um novo cache dos estilos antigos novamente porque o navegador não terminou de redimensionar o conteúdo.

Não tenho certeza se isso faz sentido por escrito, mas eu tenho que colocar um alfinete nisso por agora. Avise-me se alguém estiver alterando com sucesso seu conteúdo dinamicamente e mantendo estilos de altura atualizados.

Eu tenho muitas outras implementações de janela de reação, então eu realmente prefiro encontrar uma boa solução aqui em vez de usar a virtualização de reação para este único caso de uso.


EDIT 3: Esta será minha edição final, já que finalmente encontrei uma solução semi-elegante.

1.) Se o itemData precisa ser alterado (ou seja, quando a conversa está mudando), desmonte todo o componente e, em seguida, monte-o novamente com o novo itemData. Isso pode ser feito usando um retorno de chamada setState. Isso garante que estilos de altura antigos não sejam transportados quando você altera seus dados.

2.) Passei {sizeMap, setSize, listRef} para ChatMessage por meio de ChatContext . Dessa forma, em vez de apenas definir o tamanho às cegas, posso dizer ao ChatMessage para definir o tamanho E compará-lo com o tamanho antigo. Se o tamanho antigo for diferente do novo, chame resetAfterIndex começando em index e passando verdadeiro para forçar a atualização.

Então, meu novo ChatMessage se parece com isto:

const ChatMessage = ({ message, index }) => {
    const { setSize, sizeMap, listRef } = useContext(ChatContext);
    const root = React.useRef();
    useEffect(() => {
        let oldSize = sizeMap[index];
        let newSize = root.current.getBoundingClientRect().height;
        setSize(index, newSize);
        if(newSize !== oldSize){
            listRef.current.resetAfterIndex(index,true);
        }
    }, [sizeMap, setSize, listRef]);

    return (
        <div ref={root}
             {message.body}
        </div>
    );
};
export default ChatMessage;

3.) Eu adicionei o que é basicamente um ouvinte no componente que espera pelo recém-montado a ser processado. Depois de renderizado, ele rola para o final. Isso corrige o problema de tentar colocar a função scrollTo diretamente em componentDidMount porque ela nunca é renderizada antes de o método ser chamado. Então se parece com isso:

class Chat extends Component {
    constructor(props) {
        super(props);
        this.listRef = createRef();
        this.state = {
            initialScrollComplete: false,
            interval: null
        };
    }

    componentDidMount(){
        // Create interval to check if list is ready. Once ready, scroll to bottom of list.
        this.setState({interval: setInterval(()=>{
            if(this.listRef.current && !this.state.initialScrollComplete){
                this.listRef.current.scrollToItem(this.props.chatHistory.length - 1, "end");
                this.setState({initialScrollComplete: true});
            }
        },25)});
    }

    componentDidUpdate(prevProps, prevState) {

        // Clear interval if scroll has been completed
        if(!prevState.initialScrollComplete && this.state.initialScrollComplete){
            clearInterval(this.state.interval);
            this.setState({interval: null});
        }

        // If new message is transmitted, scroll to bottom
        if(prevProps.chatHistory && this.props.chatHistory && prevProps.chatHistory.length !== this.props.chatHistory.length){
            this.listRef.current.scrollToItem(this.props.chatHistory.length - 1, "end");
        }

    }

    render() {
        return <ChatHistory listRef={this.listRef} chatHistory={this.props.chatHistory}/>;
    }
}

Parece haver um comportamento muito estranho no safári.

A altura do div DynamicSizedList e a altura ou margem superior das linhas não funcionam corretamente, o conteúdo começa a se sobrepor.

Quando a largura da janela / conteúdo da linha muda, a nova altura não é recalculada ou alterada para funcionar com a nova altura do conteúdo.

Algo que parece consertar é se o conteúdo é rolável, rolando para um ponto onde a linha não é mais visível, rolando de volta para ele faz com que seja renderizado corretamente.

O conteúdo não é renderizado corretamente no primeiro carregamento da página, portanto, a atualização não parece resolver o problema: /

Tudo funciona perfeitamente bem em outros navegadores, incluindo Chrome e Firefox. O Safari é péssimo, mas infelizmente o aplicativo ainda precisa funcionar para as pessoas que o usam.

Screenshot 2020-02-15 at 14 27 19

Eu poderia realmente usar alguma ajuda!

@tastyqbit Também tive o mesmo problema no Safari e no Internet Explorer. Como você mencionou, rolar para além da linha expandida e, em seguida, rolar para trás permite renderizar corretamente, mas é claro que isso não resolve realmente o problema.

Se você encontrar alguma solução alternativa, por favor me avise!

@afreix @tastyqbit Tenho MDN para tabelas de compatibilidade.

Acho que a falta do ResizeObserver deve gerar um aviso no console.

Que tal algo como este https://codesandbox.io/s/agited-jennings-o9nn6 ?

básico usando VariableSizeList + ItemMeasurer de # 102 Eu sei que essa é uma abordagem muito ingênua, mas parece que está funcionando (não é tão ruim assim 😂) como solução temporária 🤔

Em nossa equipe, encontramos a necessidade de renderizar uma grande lista de dados textuais de tamanho aleatório.
Para nós, a capacidade de saltar com precisão entre os itens e rolar sem atrasos era uma obrigação.
Depois de um pouco de pesquisa online, desisti e escrevi esta biblioteca .
Espero que ajude como uma solução temporária para alguns de vocês: smile_cat:

Ei,
Só queria atualizar isso, depois de algum trabalho, acho que a biblioteca ficou em um estado decente e poderia ser uma boa solução se seus itens não mudassem de tamanho depois de serem renderizados pela primeira vez.

@ gnir-work e se a janela for redimensionada e o tamanho do contêiner mudar, fazendo com que a lista seja redimensionada?

Lendo este tópico, acho que pode haver uma maneira melhor de lidar com itens que têm uma largura que pode mudar.

A definição de 'variável' aqui é variável em todo o conjunto. O tamanho real dos itens é estático, não dinâmico. Talvez dinâmico seja um termo melhor porque o tamanho pode mudar durante o redimensionamento ou mutação se o texto mudar.

A maneira como isso pode funcionar é ouvir a rolagem do pai.

O algoritmo funcionaria assim:

  • calcule um tamanho estimado para cada item - isso precisa ser muito eficiente. Não precisa ser perfeito. + - 20% está bem.

  • nós apenas renderizamos itens que são visíveis + digamos 20% a mais para que se o usuário rolar ele não veja nenhuma mudança

  • Temos um 'fantasma' para tudo o mais que tem 'altura' definida para a altura estimada. É apenas um div vazio. Dessa forma, a barra de rolagem parece estar certa.

  • Um item só é mostrado quando está na janela de exibição. Fora isso, os itens fantasmas são mostrados.

A única desvantagem disso é que a altura da barra de rolagem mudará ligeiramente. Não tenho certeza se isso distrairia o usuário. Pode ser se a lista de rolagem for grande. PODEMOS ser capazes de enganar isso aumentando / diminuindo um buffer de forma que os tamanhos estimados não afetem o comprimento da barra de rolagem.

@ gnir-work e se a janela for redimensionada e o tamanho do contêiner mudar, fazendo com que a lista seja redimensionada?

A partir da última versão ( 2.2.0 ), o componente suporta alterações no tamanho de toda a lista (altura e largura).

Lendo este tópico, acho que pode haver uma maneira melhor de lidar com itens que têm uma largura que pode mudar.

A definição de 'variável' aqui é variável em todo o conjunto. O tamanho real dos itens é estático, não dinâmico. Talvez dinâmico seja um termo melhor porque o tamanho pode mudar durante o redimensionamento ou mutação se o texto mudar.

A maneira como isso pode funcionar é ouvir a rolagem do pai.

O algoritmo funcionaria assim:

  • calcule um tamanho estimado para cada item - isso precisa ser muito eficiente. Não precisa ser perfeito. + - 20% está bem.
  • nós apenas renderizamos itens que são visíveis + digamos 20% a mais para que se o usuário rolar ele não veja nenhuma mudança
  • Temos um 'fantasma' para tudo o mais que tem 'altura' definida para a altura estimada. É apenas um div vazio. Dessa forma, a barra de rolagem parece estar certa.
  • Um item só é mostrado quando está na janela de exibição. Fora isso, os itens fantasmas são mostrados.

A única desvantagem disso é que a altura da barra de rolagem mudará ligeiramente. Não tenho certeza se isso distrairia o usuário. Pode ser se a lista de rolagem for grande. PODEMOS ser capazes de enganar isso aumentando / diminuindo um buffer de forma que os tamanhos estimados não afetem o comprimento da barra de rolagem.

Isso já foi implementado por @bvaughn em react-virtualized . A principal desvantagem dessa abordagem é que pular para uma linha específica não funciona bem e cria bugs visuais ao rolar para cima.

@ gnir-work ah .. ok ... talvez eu aborte meu trabalho e veja o virtualizado reat

Acho que você está certo com os problemas de rolagem para cima, mas acho que posso consertar isso tendo um 'tamanho estimado' e, em seguida, convertê-lo para um tamanho real assim que o componente for montado.

... mas outro problema, é claro, é lidar com conteúdo dinâmico. Se algo atualiza, a altura do componente muda.

Se o tamanho estimado for preciso, então pode funcionar. Por exemplo, eu implementei há algum tempo uma lista virtualizada com altura dinâmica com react-virtualized e funcionou bem desde que o tamanho estimado fosse exato. Caso contrário, a funcionalidade de rolar para linha quebraria meu aplicativo ☹

Enviado do Mail para Windows 10

De: Kevin Burton
Enviado: terça-feira, 14 de abril de 2020 23:07
Para: bvaughn / react-window
Cc: Nir Geller; Menção
Assunto: Re: [bvaughn / react-window] Suporte ao conteúdo medido just-in-time (# 6)

@ gnir-work ah .. ok ... talvez eu aborte meu trabalho e veja o virtualizado reat
Acho que você está certo com os problemas de rolagem para cima, mas acho que posso consertar isso tendo um 'tamanho estimado' e, em seguida, convertê-lo para um tamanho real assim que o componente for montado.
... mas outro problema, é claro, é lidar com conteúdo dinâmico. Se algo atualiza, a altura do componente muda.
-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub ou cancele a inscrição.

-
Este e-mail foi verificado em busca de vírus pelo software antivírus Avast.
https://www.avast.com/antivirus

@ gnir-work ah ... Não preciso da funcionalidade 'rolar para a linha', acho ... embora talvez esteja errado.

Que isso seja suficiente para as suas necessidades 😊

Enviado do Mail para Windows 10

De: Kevin Burton
Enviado: terça-feira, 14 de abril de 2020 23:13
Para: bvaughn / react-window
Cc: Nir Geller; Menção
Assunto: Re: [bvaughn / react-window] Suporte ao conteúdo medido just-in-time (# 6)

@ gnir-work ah ... Não preciso da funcionalidade 'rolar para a linha', acho ... embora talvez esteja errado.
-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub ou cancele a inscrição.

-
Este e-mail foi verificado em busca de vírus pelo software antivírus Avast.
https://www.avast.com/antivirus

Como solução alternativa se:

  • a altura da linha da sua lista depende apenas do texto interno (mais talvez alguns elementos com dimensões determinadas)
  • e sua lista tem largura fixa

você pode usar CanvasRenderingContext2D.measureText () para calcular a altura da linha em vez de renderizar o componente inteiro: cocô:

CodeSandbox

@bvaughn Algum plano de publicar uma nova versão alfa no npm? Não tivemos nenhuma atualização desde 1.6.0-alpha.1 😕

@bvaughn alguma atualização? será corrigido nas versões recentes?

Para aqueles que desejam usar Typescript com DynamicSizeList - o aumento do módulo pode fornecer os tipos necessários para DynamicSizeList trabalhar fora das definições DefinitelyTyped (uma solução alternativa para minha consulta postada neste tópico no ano passado).

Adicione o seguinte ao projeto:

import React, { Component } from 'react'

declare module 'react-window' {
  export type DynamicSizeListProps = Omit<FixedSizeListProps, 'itemSize' | 'scrollToItem'>
  export class DynamicSizeList extends Component<DynamicSizeListProps> {}
}

Em seguida, importe como de costume:

import {
  DynamicSizeList,
  DynamicSizeListProps,
} from 'react-window'

// use as normal...

@types/react-window ainda precisa ser instalado primeiro para a definição FixedSizeListProps .

Obrigado pelos typedefs, vou adicioná-los agora! Estou usando DynamicSizeList em produção há mais de um ano. Atualmente baseado neste fork: "@john-osullivan/react-window-dynamic-fork": "^1.9.0-alpha.1" (ainda é a coisa mais atualizada?). Tentei mudar para react-virtuoso por causa da incerteza sobre se / quando isso seria realmente liberado. Mas descobri que tem menos desempenho e travou com isso.

@bvaughn ainda é hora de pavimentar o caminho da vaca e liberar isso para o npm? Talvez apenas renomeado para ExperimentalDynamicSizeList se você ainda estiver preocupado com ele não estar pronto.

Olá, pessoal! Obrigado pelo seu trabalho árduo e esta ótima biblioteca. Estou muito ansioso por esse recurso! No entanto, gostaria de sugerir adicionar informações sobre este assunto ao README e documentação / exemplos. Levei algum tempo para descobrir que o conteúdo dinâmico não é realmente suportado pela biblioteca e só é útil para itens com tamanho fixo / conhecido. Eu acredito que o README tem uma boa seção de FAQ onde isto pode ser adicionado.

se você estiver procurando por uma tabela / grade / árvore, este seria um bom começo https://autodesk.github.io/react-base-table/examples/dynamic-row-heights , construído em VariableSizeGrid

@ tony-scio, você pode compartilhar uma caixa de códigos e códigos de trabalho para usar DynamicSizeList de 1.6.0-alpha.1 com InfiniteLoader? Obrigado, eu realmente aprecio isso.

Alguém conseguiu fazer isso funcionar com react-beautiful-dnd? Arrastar parece fazer os itens pularem uns sobre os outros.

Alguém conseguiu fazer isso funcionar com react-beautiful-dnd? Arrastar parece fazer os itens pularem uns sobre os outros.

Eu também vou esperar por esta resposta: D

[AJUDA]
Não há código para mostrar neste link:
dynamic-size-list-vertical
e eu preciso dessa habilidade.
OBRIGADO

[AJUDA]
Não há código para mostrar neste link:
dynamic-size-list-vertical
e eu preciso dessa habilidade.
OBRIGADO

https://react-window-next.now.sh/#/examples/list/dynamic -size

alguma atualização disso? Precisamos de algo semelhante quanto possível (geralmente é muito poucos, mas em alguns casos pode ser muito) renderizar uma grande lista de itens de grade responsiva (suas alturas são dinâmicas e mudarão no celular conforme vários envios de texto, etc.). Acho que react-window seria uma virada de jogo se pudesse lidar com esse caso de uso. Se não, existem alternativas confiáveis?

alguma atualização disso? Precisamos de algo semelhante quanto possível (geralmente é muito poucos, mas em alguns casos pode ser muito) renderizar uma grande lista de itens de grade responsiva (suas alturas são dinâmicas e mudarão no celular conforme vários envios de texto, etc.). Acho que react-window seria uma virada de jogo se pudesse lidar com esse caso de uso. Se não, existem alternativas confiáveis?

@JavaJamie, já que você pediu alternativas especificamente - a biblioteca react -virtuoso vem com suporte integrado para medição de conteúdo dinâmico. Isenção de responsabilidade: eu sou o autor disso.

@JavaJamie, já que você pediu alternativas especificamente - a biblioteca react -virtuoso vem com suporte integrado para medição de conteúdo dinâmico. Isenção de responsabilidade: eu sou o autor disso.

react-virtuoso também tem o dobro do tamanho da janela react. Sempre tenha que manter o tamanho da dependência em mente.

https://bundlephobia.com/[email protected]
https://bundlephobia.com/[email protected]

Aceitei o fato de não ter tempo nem energia para terminar esse esforço. Se alguém quiser intervir e terminar o ramo que comecei, gostaria de receber sua ajuda. (Consulte também a edição # 302 para saber como isso se encaixaria no lançamento da versão dois como os novos componentes List e Grid .)

Acabamos implementando algo do zero para isso, usando sensores de visibilidade que funcionaram muito bem.

Eu provavelmente poderia fazer o OSS ou apontar para vocês o lugar certo se vocês quiserem extraí-lo e criar um novo projeto ou movê-lo aqui.

Um truque é que usamos 'blocos' para aumentar o desempenho. Basicamente, pegamos cada linha e a colocamos em um bloco pai de 25 itens, e então trocamos quando necessário.

@burtonator seria muito útil

Alguém pode fornecer uma implementação livre de bugs de react-select com DynamicSizeList?
Não consigo fazer funcionar bem juntos.
Atualmente, eu enfrento 2 problemas (desculpe por nenhuma captura de tela):

  1. Todos os itens têm style={position: absolute, left: 0, top: 0} que não me permite usar este estilo, pois todas as opções ficam em cima umas das outras.
  2. Se eu não usar o estilo prop, a lista é exibida bem, mas quando eu rolar um pouco, a parte da lista com opções encolhe, enquanto a altura total permanece inalterada. Assim, quando eu rolar, obtenho x pixels de opções reais e espaço em branco de comprimento x pixels.

Não foi possível encontrar nenhum exemplo funcional dos dois.
Vou observar que uso o fork 1.9.0, no Chrome.

Editar. Encontrou uma resposta aqui acima, na seção de comentários ocultos. https://github.com/bvaughn/react-window/issues/6#issuecomment -509016422

Uma simplificação do problema de rolagem seria usar a barra de rolagem para indicar o índice do item na lista em vez da posição de um pixel, se a rolagem estiver a mais de uma altura da janela de visualização de distância. Em vez de tentar "rolar para baixo" X pixels, o componente simplesmente renderiza os itens ao redor do índice desejado. No meio do caminho renderiza o item no índice N / 2 e, na parte inferior, renderiza o item no índice N-1.

Isso permitiria a rolagem direta do polegar para o meio ou final da lista, sem o atraso do polegar de rolagem enquanto o componente renderiza e calcula os tamanhos. No momento, para componentes VariableSizeList muito longos, é quase impossível rolar para a parte inferior, pois o cursor arrasta mais rápido do que o polegar de rolagem se move.

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

Questões relacionadas

maynir picture maynir  ·  4Comentários

janhesters picture janhesters  ·  3Comentários

ajayns picture ajayns  ·  3Comentários

bnikom picture bnikom  ·  3Comentários

delateurj picture delateurj  ·  3Comentários