Çok büyük tablolar ve listeler sitenizin performansını önemli ölçüde yavaşlatabilir. Sanallaştırma bu konuda size yardımcı 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 listeye örnek verilmiştir. Mümkün olduğunca hızlı kaydırmayı deneyin.
Bu neden yararlı?
Birçok satır içeren büyük bir tabloyu veya listeyi görüntülemeniz gerekebilir. Bu tür bir listedeki her öğenin yüklenmesi performansı önemli ölçüde etkileyebilir.
Liste sanallaştırma veya "pencereleme", yalnızca kullanıcıya görünen öğeleri oluşturma kavramıdır. İlk başta oluşturulan öğe 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 sayede listenin hem oluşturma hem de kaydırma performansı iyileşir.
"Pencereden" çıkan DOM düğümleri geri dönüştürülür veya kullanıcı listede aşağı kaydırdığında hemen yeni öğelerle değiştirilir. Bu sayede, oluşturulan tüm öğelerin sayısı pencerenin boyutuna bağlı olur.
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ı liste ve tablo türleri için kullanılabilecek çeşitli temel API'ler sağlar.
Sabit boyutlu listeler ne zaman kullanılır?
Eşit boyutlu öğ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ırı oluşturan işlev,
FixedSizeList
öğesine alt öğe olarak iletilir. Belirli bir öğeyle ilgili ayrıntılaraindex
bağımsız değişkeni (items[index]
) ile 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 olarak konumlandırılır. Bu işlemdenstyle
parametresi sorumludur.
Bu makalenin başlarında gösterilen Glitch örneğinde FixedSizeList
bileşeni örneği verilmiştir.
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 itemSize
özelliği için belirli bir değer yerine 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şik bileşende bu bileşenin bir örneği gösterilmektedir.
itemSize
öğesine iletilen öğe boyutu işlevi, bu örnekte satır yüksekliklerini rastgele belirler. 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
, çok boyutlu listelerin veya tabloların sanallaştırılması için de destek sağlar. Bu bağlamda, kullanıcı yatay ve dikey olarak kaydırırken görünür içeriğin "penceresi" değişir.
Benzer şekilde, belirli liste öğelerinin boyutunun 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 yükseklikler, genişlikler ve öğe sayılarının hem sütunlar hem de satırlar için temsil edilmesi gerekir.VariableSizeGrid
için, ilgili öğelere değer yerine işlevler göndererek hem sütun genişlikleri hem de satır yükseklikleri 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
Birçok web sitesi, kullanıcı sayfayı aşağı kaydırana kadar uzun bir listedeki öğeleri yüklemeyi ve oluşturmayı bekleyerek performansı iyileştirir. Genellikle "sonsuz yükleme" olarak adlandırılan bu teknik, kullanıcı sona yakın belirli bir eşiği geçtiğinde listeye yeni DOM düğümleri ekler. Bu, bir listedeki tüm öğeleri tek seferde yüklemekten daha iyi olsa da kullanıcı ekranı o kadar kaydırırsa DOM'u binlerce satır girişiyle doldurur. Bu, stil hesaplamalarını ve DOM mutasyonlarını yavaşlatarak performansı etkilemeye başlayan aşırı büyük bir DOM boyutuna neden olabilir.
Aşağıdaki şema bu durumu özetlemeye yardımcı olabilir:
Bu sorunu çözmenin en iyi yolu, bir sayfada küçük bir öğe "penceresi" tutmak için react-window
gibi bir kitaplığı kullanmaya devam etmek, ancak kullanıcı aşağı kaydırdığında yeni girişleri de yavaşça yüklemektir. Ayrı bir paket olan react-window-infinite-loader
, bunu react-window
ile mümkün kılar.
Bir üst App
bileşeninde yönetilen durum örneğini 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, sonsuz yükleyicinin kullanıcı belirli bir noktanın ötesine kaydırdığında daha fazla öğe yüklemek için geri çağırma işlevi kullanması gerektiğinden önemlidir.
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 yerleştirilmiştir.
Yükleyiciye atanan öğeler şunlardır:
isItemLoaded
: Belirli bir öğenin yüklenip yüklenmediğini kontrol eden yöntemitemCount
: Listede bulunan öğe sayısı (veya beklenen)loadMoreItems
: Liste için ek verilere çözüm bulan bir promise döndüren geri çağırma işlevi
Oluşturma özelliği, liste bileşeninin oluşturmak için kullandığı bir işlevi döndürmek için kullanılır.
Hem onItemsRendered
hem de ref
özellikleri, iletilmesi gereken özelliklerdir.
Aşağıda, sonsuz yüklemenin sanallaştırılmış bir listeyle nasıl çalışabileceğine dair bir örnek verilmiştir.
Listede aşağı kaydırırken aynı hissi alabilirsiniz ancak artık listenin sonuna yakın bir yere kaydırdığınızda rastgele bir kullanıcı API'sinden 10 kullanıcı getirme isteği gönderilir. Tüm bunlar, tek seferde yalnızca tek bir sonuç "penceresi" oluşturulurken yapılır.
Belirli bir öğenin index
özelliği kontrol edilerek, 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
}
};
Aşırı tarama
Sanallaştırılmış bir listedeki öğeler yalnızca kullanıcı sayfayı kaydırdığında değiştiğinden, yeni girişler gösterilmek üzereyken boş alan kısa bir süre yanıp sönebilir. Bunu fark etmek için bu kılavuzun önceki örneklerinden herhangi birine hızlıca göz atmayı deneyebilirsiniz.
react-window
, sanallaştırılmış listelerin kullanıcı deneyimini iyileştirmek için overscanCount
mülküne sahip öğeleri fazladan taramanıza olanak tanır. Bu sayede, görünür "pencere"nin dışında her zaman kaç öğenin oluşturulacağını tanımlayabilirsiniz.
<FixedSizeList
//...
overscanCount={4}
>
{...}
</FixedSizeList>
overscanCount
hem FixedSizeList
hem de VariableSizeList
bileşenlerinde çalışır ve varsayılan değeri 1'dir. Listenin büyüklüğüne ve her öğenin boyutuna bağlı olarak, birden fazla girişin aşırı taranması, kullanıcı ekranı kaydırdığında belirgin bir boşluk yanıp sönmesini önlemeye yardımcı olabilir. Ancak çok fazla girişi aşırı taramak performansı olumsuz yönde etkileyebilir. Sanallaştırılmış bir liste kullanmanın amacı, kullanıcının herhangi bir anda görebileceği giriş sayısını en aza indirmektir. Bu nedenle, aşırı taranan öğelerin sayısını mümkün olduğunca düşük tutmaya çalışın.
FixedSizeGrid
ve VariableSizeGrid
için, sırasıyla overscanColumnsCount
ve overscanRowsCount
özelliklerini kullanarak aşırı tarama yapılacak sütun ve satır sayısını kontrol edin.
Sonuç
Uygulamanızdaki listeleri ve tabloları sanallaştırmaya nereden başlayacağınızdan emin değilseniz aşağıdaki 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 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
'te desteklenmeyen belirli özellikler varsa ve bu işlevi kendiniz ekleyemiyorsanızreact-virtualized
'i kullanabilirsiniz.- Kullanıcı ekranı kaydırırken öğeleri gecikmeli olarak yüklemeniz gerekiyorsa sanallaştırılmış listenizi
react-window-infinite-loader
ile sarın. - Boş içeriklerin gösterilmesini önlemek için listelerinizde
overscanCount
özelliğini, tablolarınızda iseoverscanColumnsCount
veoverscanRowsCount
özelliklerini kullanın. Çok fazla girişi aşırı taramayın. Aksi takdirde performans olumsuz yönde etkilenir.