Esta é uma mistura de uma mesa infinita e um cenário de rolagem infinita. A melhor abstração que encontrei para isso é a seguinte:
Visão geral
Faça um <List>
componente que tenha um array de todos os filhos. Como não os renderizamos, é muito barato apenas alocá-los e descartá-los. Se as alocações de 10k forem muito grandes, você poderá passar uma função que tenha um intervalo e retornar os elementos.
<List>
{thousandelements.map(function() { return <Element /> })}
</List>
Seu List
componente está monitorando qual é a posição de rolagem e renderiza apenas os filhos que estão em exibição. Ele adiciona um grande div vazio no início para simular os itens anteriores que não são renderizados.
Agora, a parte interessante é que, uma vez que um Element
componente é renderizado, você mede sua altura e o armazena em seu List
. Isso permite que você calcule a altura do espaçador e saiba quantos elementos devem ser exibidos na visualização.
Imagem
Você está dizendo que quando a imagem está carregando eles fazem tudo "saltar" para baixo. A solução para isso é definir as dimensões da imagem em sua tag img:<img src="..." width="100" height="58" />
. Desta forma, o navegador não precisa esperar para baixá-lo para saber o tamanho que será exibido. Isso requer alguma infraestrutura, mas realmente vale a pena.
Se você não pode saber o tamanho com antecedência, adicione onload
ouvintes à sua imagem e, quando ela for carregada, meça sua dimensão exibida e atualize a altura da linha armazenada e compense a posição de rolagem.
Pulando em um elemento aleatório
Se você precisa pular para um elemento aleatório na lista, isso vai exigir alguns truques com a posição de rolagem, porque você não sabe o tamanho dos elementos intermediários. O que eu sugiro que você faça é calcular a média das alturas dos elementos que você já calculou e pular para a posição de rolagem da última altura conhecida + (número de elementos * média).
Como isso não é exato, causará problemas quando você chegar à última posição válida conhecida. Quando ocorre um conflito, basta alterar a posição do scroll para corrigi-lo. Isso vai mover a barra de rolagem um pouco, mas não deve afetá-lo muito.
React Specifics
Você deseja fornecer uma chave para todos os elementos renderizados para que sejam mantidos entre os renderizadores. Existem duas estratégias: (1) ter apenas n chaves (0, 1, 2, ... n) onde n é o número máximo de elementos que você pode exibir e usar seu módulo de posição n. (2) tem uma chave diferente por elemento. Se todos os elementos compartilham uma estrutura semelhante, é bom usar (1) para reutilizar seus nós DOM. Se não o fizerem, use (2).
Eu teria apenas duas partes do estado React: o índice do primeiro elemento e o número de elementos sendo exibidos. A posição de rolagem atual e a altura de todos os elementos seriam diretamente anexadas this
. Ao usar, setState
você está, na verdade, fazendo um rerender que só deve acontecer quando o intervalo muda.
Aqui está um exemplo de lista infinita usando algumas das técnicas que descrevo nesta resposta. Vai dar certo, mas o React é definitivamente uma boa maneira de implementar uma lista infinita :)
dê uma olhada em http://adazzle.github.io/react-data-grid/index.html# Este parece ser um datagrid poderoso e de alto desempenho com recursos semelhantes ao Excel e carregamento lento / renderização otimizada (para milhões de linhas) com recursos de edição ricos (licenciados pelo MIT). Ainda não tentei em nosso projeto, mas o farei em breve.
Um ótimo recurso para pesquisar coisas como essas também é http://react.rocks/ Nesse caso, uma pesquisa de tag é útil: http://react.rocks/tag/InfiniteScroll
fonte
Eu estava enfrentando um desafio semelhante para modelar a rolagem infinita de direção única com alturas de item heterogêneas e, portanto, criei um pacote npm de minha solução:
https://www.npmjs.com/package/react-variable-height-infinite-scroller
e uma demonstração: http://tnrich.github.io/react-variable-height-infinite-scroller/
Você pode verificar o código-fonte da lógica, mas basicamente segui a receita @Vjeux delineada na resposta acima. Ainda não pulei para um item específico, mas espero implementá-lo em breve.
Esta é a essência da aparência atual do código:
fonte