Çok büyük tablolar ve listeler, sitenizin performansını önemli ölçüde yavaşlatabilir. Sanallaştırma size yardımcı olabilir.
react-window
, büyük listelerin verimli şekilde oluşturulmasına olanak tanıyan bir kitaplıktır.
react-window
ile oluşturulan 1.000 satırlık bir liste örneğini burada bulabilirsiniz. Olabildiğince hızlı kaydırmayı deneyin.
Neden yararlıdır?
Çok sayıda satır içeren büyük bir tablo veya liste göstermeniz gereken zamanlar olabilir. Böyle bir listedeki her öğ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 çok küçük bir alt kümesidir ve kullanıcı kaydırmaya devam ettiğinde görünür içerik "penceresi" hareket eder. Bu, listenin hem oluşturma hem de kaydırma performansını artırır.

"Pencere"den çıkan DOM düğümleri geri dönüştürülür veya kullanıcı listede aşağı kaydırdıkça daha yeni öğelerle hemen değiştirilir. Bu, oluşturulan tüm öğelerin sayısını pencerenin boyutuna göre belirli bir sayıda tutar.
react-window
react-window
, uygulamanızda sanallaştırılmış listeler oluşturmayı kolaylaştıran küçük bir üçüncü taraf kitaplığıdır. Farklı türlerdeki listeler ve tablolar için kullanılabilecek bir dizi temel API sunar.
Sabit boyutlu listeler ne zaman kullanılır?
Aynı boyuttaki öğelerden oluşan uzun ve 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çinheight
,width
veitemSize
özelliğini kabul eder.- Satırları oluşturma işlevi,
FixedSizeList
öğesine alt öğe olarak iletilir. Belirli bir öğeyle ilgili ayrıntılaraindex
bağımsız değişkeniyle (items[index]
) erişilebilir. - Satır oluşturma yöntemine bir
style
parametresi de aktarılır. Bu parametre, satır öğesine eklenmelidir. Liste öğeleri, yükseklik ve genişlik değerleri satır içi olarak atanmış şekilde mutlak konumlandırılır. Bu durumdanstyle
parametresi sorumludur.
Bu makalenin önceki bölümlerinde gösterilen Glitch örneğinde, FixedSizeList
bileşenine dair bir örnek yer almaktadır.
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 liste gibi çalışır ancak belirli bir değer yerine itemSize
özelliği 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 boyutlarını tanımlayan gerçek bir mantık olmalıdır. İdeal olarak bu boyutlar, verilere göre hesaplanmalı veya bir API'den alınmalıdır.
Izgaralar
react-window
ayrıca çok boyutlu listeleri veya ızgaraları sanallaştırma desteği de sunar. Bu bağlamda, kullanıcının yatay ve dikey olarak kaydırmasıyla birlikte görünür içerik "penceresi" değişir.

Benzer şekilde, belirli liste öğelerinin boyutu değişebiliyorsa hem FixedSizeGrid
hem de VariableSizeGrid
bileşenleri kullanılabilir.
FixedSizeGrid
için API yaklaşık olarak aynıdır ancak yüksekliklerin, genişliklerin ve öğe sayılarının hem sütunlar hem de satırlar için gösterilmesi gerekir.VariableSizeGrid
için, sütun genişlikleri ve satır yükseklikleri, değerler yerine işlevler iletilerek değiştirilebilir.
Sanal ızgara örnekleri için belgelere göz atın.
Kaydırma sırasında geç yükleme
Birçok web sitesi, kullanıcı aşağı kaydırana kadar uzun bir listedeki öğeleri yüklemeyi ve oluşturmayı bekleyerek performansı artırır. Genellikle "sonsuz yükleme" olarak adlandırılan bu teknik, kullanıcı sonuna yakın belirli bir eşiği geçtikçe listeye yeni DOM düğümleri ekler. Bu, listedeki tüm öğeleri aynı anda yüklemekten daha iyi olsa da kullanıcı bu kadar çok öğeyi kaydırdıysa DOM'u yine de binlerce satır girişiyle doldurur. 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 diyagram bu durumu özetlemeye yardımcı olabilir:

Bu sorunu çözmek için en iyi yaklaşım, sayfadaki öğelerin küçük bir "penceresini" korumak için react-window
gibi bir kitaplık kullanmaya devam etmek ancak kullanıcı aşağı kaydırdıkça yeni girişleri de geç yüklemektir. Ayrı bir paket olan react-window-infinite-loader
, react-window
ile bunu mümkün kılar.
Aşağıdaki kod parçası, üst App
bileşeninde yönetilen bir durum örneğini gösterir.
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 loadMore
yöntemi iletilir. Bu önemlidir. Çünkü kullanıcı belirli bir noktayı geçtikten sonra daha fazla öğe yüklemek için sonsuz yükleyicinin bir geri çağırma işlemi tetiklemesi gerekir.
Listeyi oluşturan ListComponent
öğesi şu şekilde 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 yerleştirilmiştir.
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 verilerle sonuçlanan bir söz döndüren geri çağırma
Render prop, liste bileşeninin oluşturmak için kullandığı bir işlevi döndürmek üzere kullanılır.
Hem onItemsRendered
hem de ref
özellikleri iletilmesi gereken özelliklerdir.
Aşağıda, sonsuz yüklemenin sanallaştırılmış bir listede nasıl çalışabileceğine dair bir örnek verilmiştir.
Listede aşağı kaydırmak aynı hissi verebilir ancak artık listenin sonuna yaklaştığınızda her seferinde rastgele kullanıcı API'sinden 10 kullanıcıyı almak için istek gönderilir. Tüm bunlar, tek seferde yalnızca tek bir sonuç "penceresi" oluşturulurken yapılır.
Belirli bir öğenin index
kontrol edildiğinde, yeni girişler için istek gönderilip gönderilmediğine ve öğenin hâlâ yüklenip yüklenmediğine 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
}
};
Fazla tarama
Sanal listedeki öğeler yalnızca kullanıcı kaydırdığında değiştiğinden, yeni girişler gösterilmek üzereyken boş alan kısa süreliğine yanıp sönebilir. Bunu fark etmek için bu kılavuzdaki önceki örneklerden herhangi birini hızlıca kaydırmayı deneyebilirsiniz.
Sanal listelerin kullanıcı deneyimini iyileştirmek için react-window
, öğeleri overscanCount
özelliğiyle taramanıza olanak tanır. Bu sayede, görünür "pencerenin" dışındaki kaç öğenin her zaman oluşturulacağını tanımlayabilirsiniz.
<FixedSizeList
//...
overscanCount={4}
>
{...}
</FixedSizeList>
overscanCount
hem FixedSizeList
hem de VariableSizeList
bileşenleri için çalışır ve varsayılan değeri 1'dir. Listenin büyüklüğüne ve her öğenin boyutuna bağlı olarak, birden fazla girişi aşırı taramak, kullanıcı kaydırdığında boş alanın fark edilebilir şekilde yanıp sönmesini önlemeye yardımcı olabilir. Ancak çok fazla girişi aşırı taramak performansı olumsuz etkileyebilir. Sanal liste kullanmanın asıl amacı, giriş sayısını kullanıcının herhangi bir anda görebileceği öğelerle sınırlamaktır. 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 aşırı tarama yapılacak sütun ve satır sayısını kontrol etmek üzere overscanColumnsCount
ve overscanRowsCount
özelliklerini kullanın.
Sonuç
Uygulamanızdaki listeleri ve tabloları nerede sanallaştırmaya 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çer'in, öğelerin bir listede ne kadar verimli şekilde oluşturulduğunu incelemek için nasıl kullanılabileceği gösterilmektedir.
- Performansı etkileyen uzun listeler veya tablolar için
react-window
özelliğini ekleyin. react-window
'da desteklenmeyen belirli özellikler varsa bu işlevleri kendiniz ekleyemiyorsanızreact-virtualized
'ı kullanmayı düşünebilirsiniz.- Kullanıcı kaydırdıkça öğ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 listelerinizde
overscanCount
özelliğini, ızgaralarınızda iseoverscanColumnsCount
veoverscanRowsCount
özelliklerini kullanın. Çok fazla girişi taramayın. Aksi takdirde performans olumsuz etkilenir.