Ç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ı?
Birden çok satır içeren büyük bir tablo veya liste görüntülemeniz gereken durumlar olabilir. 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ı, tüm 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 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 sunar.
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çinheight
,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 atanmış şekilde kesinlikle konumlandırılır ve bundanstyle
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 boyut listesiyle aynı şekilde çalışır, ancak bunun yerine 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ş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ırdığında görünen 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üksekliklerin, genişliklerin 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 geçirilerek hem sütun genişlikleri hem de satır yükseklikleri değiştirilebilir.
Sanallaştırılmış ızgara örneklerini görmek için dokümanlara göz atın.
Kaydırırken 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çerken 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 çok kaydırmışsa 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 önemlidir, çünkü sonsuz yükleyicinin, kullanıcı belirli bir noktayı kaydırdıktan sonra daha fazla öğe yüklemek için bir geri çağırma 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 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. Bunların tümü, aynı anda 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
}
};
Fazla 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, her zaman görünen "pencere"nin dışında kaç öğenin 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şin aşırı taranması, kullanıcı ekranı kaydırdığında belirgin bir boşluk yanıp sönmesini önlemeye yardımcı olabilir. Bununla birlikte, çok fazla girişin aşırı taranması 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, geçersiz kılınacak sütun ve satır sayısını sırasıyla kontrol etmek için overscanColumnsCount
ve overscanRowsCount
özelliklerini kullanın.
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ı sayfayı kaydırırken öğeleri geç yüklemeniz gerekiyorsa sanallaştırılmış listenizi
react-window-infinite-loader
ile sarmalayı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 etkilenir.