Çok büyük tablolar ve listeler sitenizin performansını önemli ölçüde yavaşlatabilir. Sanallaştırma faydalı olabilir.
react-window
, büyük listelerin verimli bir şekilde oluşturulmasına olanak tanıyan bir kitaplıktır.
react-window
ile oluşturulan 1.000 satır içeren bir liste örneğini burada bulabilirsiniz. Olabildiğince hızlı kaydırmayı deneyin.
Neden faydalı oldu?
Çok sayıda satır içeren büyük bir tablo veya liste görüntülemeniz gereken zamanlar olabilir. Böyle bir listedeki her bir öğenin yüklenmesi, performansı önemli ölçüde etkileyebilir.
Liste sanallaştırma veya "pencereleme", yalnızca kullanıcının görebildiği öğelerin oluşturulmasıdır. İlk başta oluşturulan öğelerin sayısı listenin tamamının çok küçük bir alt kümesidir ve kullanıcı kaydırmaya devam ettiğinde görünür içeriğin "penceresi" hareket eder. Bu, listenin hem oluşturma hem de kaydırma performansını iyileştirir.
![Sanallaştırılmış bir listedeki içerik penceresi](https://web.developers.google.cn/static/articles/virtualize-long-lists-react-window/image/window-content-a-virtua-9c3c7f0cbf9a5.jpg?authuser=5&hl=tr)
"Pencereden" çıkan DOM düğümleri geri dönüştürülür veya kullanıcı listeyi aşağı kaydırdıkça hemen yeni öğelerle değiştirilir. Bu, oluşturulan tüm öğelerin sayısını pencerenin boyutuna özel tutar.
tepki-penceresi
react-window
, uygulamanızda sanallaştırılmış listeler oluşturmayı kolaylaştıran küçük bir üçüncü taraf kitaplığıdır. Farklı liste ve tablo türleri için kullanılabilecek birçok temel API sağlar.
Sabit boyut listeleri ne zaman kullanılır?
Eşit boyutlarda öğelerden oluşan uzun, tek boyutlu bir listeniz varsa FixedSizeList
bileşenini kullanın.
import React from 'react';
import { FixedSizeList } from 'react-window';
const items = [...] // some list of items
const Row = ({ index, style }) => (
<div style={style}>
{/* define the row component using items[index] */}
</div>
);
const ListComponent = () => (
<FixedSizeList
height={500}
width={500}
itemSize={120}
itemCount={items.length}
>
{Row}
</FixedSizeList>
);
export default ListComponent;
FixedSizeList
bileşeni, listedeki öğelerin boyutunu kontrol etmek için birheight
,width
veitemSize
özelliğini kabul eder.- Satırları oluşturan bir işlev,
FixedSizeList
öğesine alt öğe olarak geçirilir. Belirli bir öğe hakkındaki ayrıntılaraindex
bağımsız değişkeniyle (items[index]
) erişilebilir. - Ayrıca, satır öğesine eklenmesi gereken satır oluşturma yöntemine bir
style
parametresi de iletilir. Liste öğeleri, yükseklik ve genişlik değerleri satır içi olarak atanacak şekilde kesinlikle konumlandırılır ve bundanstyle
parametresi sorumludur.
Bu makalenin önceki kısımlarında gösterilen Glitch örneğinde FixedSizeList
bileşeninin bir örneği gösterilmektedir.
Değişken boyutlu listeler ne zaman kullanılır?
Farklı boyutlara sahip öğelerin listesini oluşturmak için VariableSizeList
bileşenini kullanın. Bu bileşen, sabit boyutlu bir listeyle aynı şekilde çalışır ancak bunun yerine belirli bir değer yerine itemSize
önerisi için bir işlev bekler.
import React from 'react';
import { VariableSizeList } from 'react-window';
const items = [...] // some list of items
const Row = ({ index, style }) => (
<div style={style}>
{/* define the row component using items[index] */}
</div>
);
const getItemSize = index => {
// return a size for items[index]
}
const ListComponent = () => (
<VariableSizeList
height={500}
width={500}
itemCount={items.length}
itemSize={getItemSize}
>
{Row}
</VariableSizeList>
);
export default ListComponent;
Aşağıdaki yerleştirilmiş öğede bu bileşenin bir örneği gösterilmektedir.
itemSize
özelliğine iletilen öğe boyutu işlevi, bu örnekte satır yüksekliklerini rastgele hale getirir. Ancak gerçek bir uygulamada, her öğenin boyutunu tanımlayan gerçek bir mantık olmalıdır. İdeal olarak, bu boyutların verilere dayanılarak veya API'den elde edilen şekilde hesaplanması gerekir.
Izgaralar
react-window
, çok boyutlu listeleri veya ızgaraları sanallaştırmayı da destekler. Bu bağlamda, kullanıcı yatay olarak ve dikey olarak kaydırdıkça görünür içeriğin "penceresi" değişir.
![Sanallaştırılmış bir ızgarada içerik penceresinin taşınması iki boyutlu bir işlemdir](https://web.developers.google.cn/static/articles/virtualize-long-lists-react-window/image/moving-window-content-a-3393c2a96ff59.jpg?authuser=5&hl=tr)
Benzer şekilde, belirli liste öğelerinin boyutlarının değişip değişemeyeceğine bağlı olarak hem FixedSizeGrid
hem de VariableSizeGrid
bileşenleri kullanılabilir.
FixedSizeGrid
için API yaklaşık olarak aynıdır ancak hem sütunlar hem de satırlar için yüksekliklerin, genişliklerin ve öğe sayılarının temsil edilmesi gerekir.VariableSizeGrid
için hem sütun genişlikleri hem de satır yükseklikleri, değerler yerine işlevlerin ilgili sahnelere geçirilmesiyle değiştirilebilir.
Sanallaştırılmış ızgara örneklerini görmek için belgelere göz atın.
Kaydırma sırasında geç yükleme
Pek çok web sitesi, kullanıcı aşağı kaydırana kadar uzun bir listedeki öğeleri yükleyip oluşturmayı bekleyerek performansı iyileştirir. Genellikle "sonsuz yükleme" olarak adlandırılan bu teknik, kullanıcı ekranı sona doğru yaklaşan belirli bir eşiği geçerken listeye yeni DOM düğümleri ekler. Bu işlem, listedeki tüm öğeleri aynı anda yüklemekten daha iyi olsa da kullanıcı sayfayı kaydırarak bu sayıdan fazla satır geçmişse DOM yine de binlerce satır girişiyle doldurulur. Bu durum, stil hesaplamalarını ve DOM mutasyonlarını yavaşlatarak performansı etkilemeye başlayan aşırı büyük bir DOM boyutuna yol açabilir.
Aşağıdaki şema bunu özetlemenize yardımcı olabilir:
![Normal ve sanallaştırılmış liste kaydırma arasındaki fark](https://web.developers.google.cn/static/articles/virtualize-long-lists-react-window/image/difference-scrolling-bet-517c003019905.jpg?authuser=5&hl=tr)
Bu sorunu çözmek için en iyi yaklaşım, bir sayfadaki öğelerin küçük bir "penceresini" korumak ve kullanıcı sayfayı aşağı kaydırırken daha yeni girişleri geç yüklemek için react-window
gibi bir kitaplığı kullanmaya devam etmektir. Ayrı bir paket (react-window-infinite-loader
), react-window
ile bunu mümkün kılar.
Üst App
bileşeninde yönetilen bir durum örneği gösteren aşağıdaki kod parçasını inceleyin.
import React, { Component } from 'react';
import ListComponent from './ListComponent';
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [], // instantiate initial list here
moreItemsLoading: false,
hasNextPage: true
};
this.loadMore = this.loadMore.bind(this);
}
loadMore() {
// method to fetch newer entries for the list
}
render() {
const { items, moreItemsLoading, hasNextPage } = this.state;
return (
<ListComponent
items={items}
moreItemsLoading={moreItemsLoading}
loadMore={this.loadMore}
hasNextPage={hasNextPage}
/>
);
}
}
export default App;
Sonsuz yükleyici listesini içeren bir alt ListComponent
öğesine bir loadMore
yöntemi iletilir. Bu önemlidir, çünkü kullanıcı belirli bir noktayı kaydırdıktan sonra sonsuz yükleyicinin daha fazla öğe yüklemek için bir geri çağırmayı tetiklemesi gerekir.
Listeyi oluşturan ListComponent
aşağıdaki gibi görünebilir:
import React from 'react';
import { FixedSizeList } from 'react-window';
import InfiniteLoader from "react-window-infinite-loader";
const ListComponent = ({ items, moreItemsLoading, loadMore, hasNextPage }) => {
const Row = ({ index, style }) => (
{/* define the row component using items[index] */}
);
const itemCount = hasNextPage ? items.length + 1 : items.length;
return (
<InfiniteLoader
isItemLoaded={index => index < items.length}
itemCount={itemCount}
loadMoreItems={loadMore}
>
{({ onItemsRendered, ref }) => (
<FixedSizeList
height={500}
width={500}
itemCount={itemCount}
itemSize={120}
onItemsRendered={onItemsRendered}
ref={ref}
>
{Row}
</FixedSizeList>
)}
</InfiniteLoader>
)
};
export default ListComponent;
Burada, FixedSizeList
bileşeni InfiniteLoader
içine sarmalanmıştır.
Yükleyiciye atanan özellikler şunlardır:
isItemLoaded
: Belirli bir öğenin yüklenip yüklenmediğini kontrol eden yöntemitemCount
: Listedeki (veya beklenen) öğe sayısıloadMoreItems
: Liste için ek verilere çözüm sağlayan bir vaadi döndüren geri çağırma.
Oluşturma özelliği, liste bileşeninin oluşturmak üzere kullandığı bir işlevi döndürmek için kullanılır.
Hem onItemsRendered
hem de ref
özellikleri aktarılması gereken özelliklerdir.
Aşağıda, sonsuz yüklemenin sanallaştırılmış bir listeyle nasıl çalışabileceğine dair bir örnek verilmiştir.
Listenin aşağı kaydırılması da aynı şekilde hissettirilebilir ancak artık listenin sonuna doğru her kaydırdığınızda rastgele kullanıcı API'sinden 10 kullanıcı alınması için istekte bulunulur. Bunların tümü, her defasında yalnızca tek bir sonuç "penceresi" oluşturulurken yapılır.
Belirli bir öğenin index
özelliği kontrol edildiğinde, daha yeni girişler için istekte bulunulmuş olup olmamasına bağlı olarak öğe için farklı bir yükleme durumu gösterilebilir.
Örneğin:
const Row = ({ index, style }) => {
const itemLoading = index === items.length;
if (itemLoading) {
// return loading state
} else {
// return item
}
};
Aşırı tarama
Sanallaştırılmış bir listedeki öğeler yalnızca kullanıcı sayfayı kaydırdığında değiştiğinden, daha yeni girişler gösterilmek üzereyken boş alanlar kısa süreliğine yanıp sönebilir. Bunu fark etmek için bu kılavuzda önceki örneklerden herhangi birini hızlıca kaydırmayı deneyebilirsiniz.
react-window
, sanallaştırılmış listelerin kullanıcı deneyimini iyileştirmek için overscanCount
özelliğini kullanarak öğeleri aşırı taramanıza olanak tanır. Bu, her zaman görünür "pencere" dışında kaç tane öğenin oluşturulacağını tanımlamanıza olanak tanır.
<FixedSizeList
//...
overscanCount={4}
>
{...}
</FixedSizeList>
overscanCount
, hem FixedSizeList
hem de VariableSizeList
bileşenleri için çalışır ve 1 varsayılan değerine sahiptir. Bir listenin ne kadar büyük olduğuna ve her bir öğenin boyutuna bağlı olarak, birden fazla girişten fazla tarama yapmak, kullanıcı ekranı kaydırdığında fark edilebilir bir boş alan yanıp sönmesini önlemeye yardımcı olabilir. Ancak çok fazla girişin aşırı taranması performansı olumsuz etkileyebilir. Sanallaştırılmış bir liste kullanmanın asıl amacı, giriş sayısını kullanıcının herhangi bir anda görebileceği giriş sayısını en aza indirmektir. Bu nedenle, fazla taranan öğelerin sayısını mümkün olduğunca düşük tutmaya çalışın.
FixedSizeGrid
ve VariableSizeGrid
için sırasıyla, taşacak sütun ve satır sayısını kontrol etmek üzere overscanColumnsCount
ve overscanRowsCount
özelliklerini kullanın.
Sonuç
Uygulamanızda listeleri ve tabloları sanallaştırmaya nereden başlayacağınızdan emin değilseniz şu adımları uygulayın:
- Oluşturma ve kaydırma performansını ölçün. Bu makalede, Chrome Geliştirici Araçları'ndaki FPS ölçerin, bir listedeki öğelerin ne kadar verimli bir şekilde oluşturulduğunu keşfetmek için nasıl kullanılabileceği gösterilmektedir.
- Performansı etkileyen uzun listeler veya ızgaralar için
react-window
ekleyin. react-window
ürününde desteklenmeyen özellikler varsa ve bu işlevi kendiniz ekleyemiyorsanızreact-virtualized
kullanmayı düşünebilirsiniz.- Kullanıcı ekranı kaydırırken öğeleri geç yüklemeniz gerekiyorsa sanallaştırılmış listenizi
react-window-infinite-loader
ile sarmalayın. - Boş içeriklerin yanıp sönmesini önlemek için listeleriniz için
overscanCount
özelliğini ve ızgaralarınız içinoverscanColumnsCount
ileoverscanRowsCount
özelliklerini kullanın. Performansı olumsuz yönde etkileyeceğinden çok fazla sayıda giriş taraması yapmayın.