لیست های بزرگ را با react-window مجازی سازی کنید

جداول و لیست های بسیار بزرگ می توانند عملکرد سایت شما را به طور قابل توجهی کاهش دهند. مجازی سازی می تواند کمک کند!

react-window کتابخانه ای است که به لیست های بزرگ اجازه می دهد تا به طور موثر ارائه شوند.

در اینجا نمونه ای از لیستی است که شامل 1000 ردیف است که با react-window ارائه می شود. هر چه سریعتر اسکرول کنید.

چرا این مفید است؟

ممکن است زمان هایی وجود داشته باشد که شما نیاز به نمایش جدول یا لیست بزرگی داشته باشید که دارای ردیف های زیادی است. بارگیری تک تک موارد در چنین لیستی می تواند عملکرد قابل توجهی را تحت تأثیر قرار دهد.

مجازی‌سازی فهرست یا «پنجره‌سازی» مفهومی است که تنها آنچه را که برای کاربر قابل مشاهده است ارائه می‌کند. تعداد عناصری که در ابتدا رندر می شوند، زیرمجموعه بسیار کوچکی از کل لیست است و زمانی که کاربر به پیمایش ادامه می دهد، «پنجره» محتوای قابل مشاهده حرکت می کند . این کار هم عملکرد رندر و هم عملکرد اسکرول لیست را بهبود می بخشد.

پنجره محتوا در یک لیست مجازی
جابجایی "پنجره" محتوا در یک لیست مجازی

گره‌های DOM که از «پنجره» خارج می‌شوند، بازیافت می‌شوند یا بلافاصله با اسکرول کردن کاربر در فهرست با عناصر جدیدتر جایگزین می‌شوند. با این کار تعداد تمام عناصر رندر شده مخصوص اندازه پنجره حفظ می شود.

پنجره واکنش

react-window یک کتابخانه کوچک و شخص ثالث است که ایجاد لیست های مجازی در برنامه شما را آسان تر می کند. تعدادی API پایه را ارائه می دهد که می توانند برای انواع مختلف لیست ها و جداول استفاده شوند.

زمان استفاده از لیست های اندازه ثابت

اگر فهرستی طولانی و تک بعدی از اقلام با اندازه یکسان دارید، از مؤلفه FixedSizeList استفاده کنید.

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 height ، width و itemSize را برای کنترل اندازه آیتم های موجود در لیست می پذیرد.
  • تابعی که ردیف ها را رندر می کند به عنوان فرزند به FixedSizeList ارسال می شود. جزئیات مربوط به یک مورد خاص را می توان با آرگومان index ( items[index] ) در دسترس قرار داد.
  • یک پارامتر style نیز به روش رندر ردیف ارسال می شود که باید به عنصر ردیف متصل شود. آیتم‌های فهرست کاملاً با مقادیر ارتفاع و عرض آن‌ها که به صورت خطی تخصیص داده شده است، قرار می‌گیرند و پارامتر style مسئول این است.

مثال Glitch که قبلا در این مقاله نشان داده شد، نمونه ای از یک جزء FixedSizeList را نشان می دهد.

زمان استفاده از لیست های با اندازه متغیر

از مؤلفه VariableSizeList برای ارائه فهرستی از مواردی که اندازه های متفاوتی دارند استفاده کنید. این کامپوننت مانند یک لیست اندازه ثابت کار می کند، اما در عوض به جای یک مقدار خاص، یک تابع برای prop itemSize انتظار دارد.

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;

تعبیه زیر نمونه ای از این کامپوننت را نشان می دهد.

تابع اندازه آیتم که به prop itemSize ارسال می شود، ارتفاع ردیف را در این مثال تصادفی می کند. با این حال، در یک برنامه واقعی، باید منطق واقعی وجود داشته باشد که اندازه هر آیتم را تعریف کند. در حالت ایده آل، این اندازه ها باید بر اساس داده ها محاسبه شوند یا از یک API به دست آیند.

شبکه ها

react-window همچنین از مجازی سازی لیست ها یا شبکه های چند بعدی پشتیبانی می کند. در این زمینه، "پنجره" محتوای قابل مشاهده با حرکت کاربر به صورت افقی و عمودی تغییر می کند.

جابجایی پنجره محتوا در یک شبکه مجازی شده دو بعدی است
جابجایی "پنجره" محتوا در یک شبکه مجازی شده دو بعدی است

به طور مشابه، هر دو مؤلفه FixedSizeGrid و VariableSizeGrid را می توان بسته به اینکه آیا اندازه آیتم های لیست خاص می تواند متفاوت باشد، استفاده می شود.

  • برای FixedSizeGrid ، API تقریباً یکسان است، اما با این واقعیت که ارتفاع، عرض و تعداد آیتم‌ها باید برای ستون‌ها و سطرها نمایش داده شوند.
  • برای VariableSizeGrid ، هم عرض ستون و هم ارتفاع سطر را می توان با انتقال توابع به جای مقادیر به props مربوطه تغییر داد.

برای مشاهده نمونه هایی از شبکه های مجازی سازی شده به مستندات نگاهی بیندازید.

بارگذاری تنبل در اسکرول

بسیاری از وب‌سایت‌ها با صبر کردن برای بارگیری و ارائه آیتم‌ها در یک لیست طولانی تا زمانی که کاربر به پایین پیمایش کند، عملکرد را بهبود می‌بخشند. این تکنیک که معمولاً به عنوان "بارگذاری بی نهایت" نامیده می شود، گره های DOM جدیدی را به لیست اضافه می کند، زیرا کاربر از آستانه مشخصی نزدیک به انتها عبور می کند. اگرچه این بهتر از بارگیری همه موارد در یک لیست به طور همزمان است، اما اگر کاربر از این تعداد ردیف گذشته باشد، همچنان DOM را با هزاران ورودی ردیف پر می کند. این می تواند منجر به یک اندازه DOM بسیار بزرگ شود که با کندتر کردن محاسبات سبک و جهش های DOM شروع به تأثیر بر عملکرد می کند.

نمودار زیر می تواند به خلاصه کردن این موضوع کمک کند:

تفاوت در اسکرول بین لیست معمولی و مجازی
تفاوت در اسکرول بین لیست معمولی و مجازی

بهترین رویکرد برای حل این مشکل، ادامه استفاده از کتابخانه‌ای مانند react-window برای حفظ یک "پنجره" کوچک از عناصر در یک صفحه است، اما همچنین بارگذاری تنبل ورودی‌های جدیدتر هنگام حرکت کاربر به پایین است. یک بسته جداگانه، react-window-infinite-loader ، این کار را با react-window امکان پذیر می کند.

قطعه کد زیر را در نظر بگیرید که نمونه ای از وضعیت را نشان می دهد که در یک مؤلفه App والد مدیریت می شود.

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;

یک متد loadMore به یک ListComponent فرزند ارسال می‌شود که حاوی لیست لودر بی‌نهایت است. این مهم است زیرا لودر بی‌نهایت باید برای بارگیری موارد بیشتر، زمانی که کاربر از نقطه خاصی عبور کرده است، یک تماس برگشتی ایجاد کند.

در اینجا ListComponent که لیست را رندر می کند، می تواند شبیه به این باشد:

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;

در اینجا، مؤلفه FixedSizeList درون InfiniteLoader پیچیده شده است. قطعات تخصیص داده شده به لودر عبارتند از:

  • isItemLoaded : روشی که بررسی می کند آیا یک آیتم خاص بارگذاری شده است یا خیر
  • itemCount : تعداد موارد موجود در لیست (یا مورد انتظار)
  • loadMoreItems : Callback که وعده ای را برمی گرداند که به داده های اضافی لیست حل می شود

یک پروپ رندر برای برگرداندن تابعی استفاده می شود که جزء لیست از آن برای رندر کردن استفاده می کند. هر دو ویژگی onItemsRendered و ref ویژگی هایی هستند که باید به آنها منتقل شوند.

در زیر مثالی از نحوه کار بارگذاری بی نهایت با یک لیست مجازی ارائه شده است.

اسکرول کردن به پایین لیست ممکن است همین احساس را داشته باشد، اما اکنون درخواستی برای بازیابی 10 کاربر از یک API تصادفی کاربر هر بار که به انتهای لیست نزدیک می شوید، ارسال می شود. این همه در حالی انجام می شود که تنها یک "پنجره" از نتایج در یک زمان ارائه می شود.

با بررسی index یک آیتم خاص، بسته به اینکه آیا درخواستی برای ورودی های جدیدتر انجام شده و آیتم هنوز در حال بارگیری است، می توان وضعیت بارگیری متفاوتی را برای یک آیتم نشان داد.

به عنوان مثال:

const Row = ({ index, style }) => {
  const itemLoading = index === items.length;

  if (itemLoading) {
      // return loading state
  } else {
      // return item
  }
};

Overscanning

از آنجایی که موارد موجود در یک لیست مجازی تنها زمانی تغییر می‌کنند که کاربر پیمایش کند، فضای خالی می‌تواند برای مدت کوتاهی چشمک بزند، زیرا ورودی‌های جدیدتر نمایش داده می‌شوند. می‌توانید هر یک از نمونه‌های قبلی را در این راهنما به سرعت پیمایش کنید تا متوجه این موضوع شوید.

برای بهبود تجربه کاربری لیست های مجازی شده، react-window به شما امکان می دهد موارد را با ویژگی overscanCount اسکن کنید. این به شما امکان می‌دهد تا در همه زمان‌ها تعداد آیتم‌های خارج از پنجره قابل مشاهده را تعریف کنید.

<FixedSizeList
  //...
  overscanCount={4}
>
  {...}
</FixedSizeList>

overscanCount برای هر دو مؤلفه FixedSizeList و VariableSizeList کار می کند و مقدار پیش فرض آن 1 است. بسته به بزرگی یک لیست و همچنین اندازه هر مورد، اسکن بیش از حد بیش از یک ورودی می تواند به جلوگیری از فلش محسوس فضای خالی در هنگام اسکرول کردن کاربر کمک کند. با این حال، اسکن بیش از حد ورودی‌ها می‌تواند بر عملکرد تأثیر منفی بگذارد. هدف اصلی استفاده از یک لیست مجازی، به حداقل رساندن تعداد ورودی ها به آنچه کاربر در هر لحظه می تواند ببیند است، بنابراین سعی کنید تعداد موارد بیش از حد اسکن شده را تا حد امکان کم نگه دارید.

برای FixedSizeGrid و VariableSizeGrid ، از ویژگی‌های overscanColumnsCount و overscanRowsCount برای کنترل تعداد ستون‌ها و ردیف‌ها برای اسکن بیش‌ازحد استفاده کنید.

نتیجه گیری

اگر مطمئن نیستید که از کجا مجازی سازی لیست ها و جداول را در برنامه خود شروع کنید، این مراحل را دنبال کنید:

  1. عملکرد رندر و پیمایش را اندازه گیری کنید. این مقاله نشان می‌دهد که چگونه می‌توان از FPS متر در Chrome DevTools برای بررسی میزان کارآمد بودن موارد در فهرست استفاده کرد.
  2. برای هر لیست طولانی یا شبکه‌هایی که بر عملکرد تأثیر می‌گذارند، react-window اضافه کنید.
  3. اگر ویژگی‌های خاصی در react-window پشتیبانی نمی‌شوند، اگر خودتان نمی‌توانید این قابلیت را اضافه کنید، از react-virtualized استفاده کنید.
  4. در صورت نیاز به بارگذاری تنبل آیتم ها در حین حرکت کاربر، لیست مجازی خود را با react-window-infinite-loader بپیچید.
  5. از ویژگی overscanCount برای لیست های خود و از ویژگی های overscanColumnsCount و overscanRowsCount برای شبکه های خود استفاده کنید تا از فلش محتوای خالی جلوگیری کنید. از اسکن بیش از حد ورودی ها خودداری کنید زیرا این کار بر عملکرد تأثیر منفی می گذارد.
،

جداول و لیست های بسیار بزرگ می توانند عملکرد سایت شما را به طور قابل توجهی کاهش دهند. مجازی سازی می تواند کمک کند!

react-window کتابخانه ای است که به لیست های بزرگ اجازه می دهد تا به طور موثر ارائه شوند.

در اینجا نمونه ای از لیستی است که شامل 1000 ردیف است که با react-window ارائه می شود. هر چه سریعتر اسکرول کنید.

چرا این مفید است؟

ممکن است زمان هایی وجود داشته باشد که شما نیاز به نمایش جدول یا لیست بزرگی داشته باشید که دارای ردیف های زیادی است. بارگیری تک تک موارد در چنین لیستی می تواند عملکرد قابل توجهی را تحت تأثیر قرار دهد.

مجازی‌سازی فهرست یا «پنجره‌سازی» مفهومی است که تنها آنچه را که برای کاربر قابل مشاهده است ارائه می‌کند. تعداد عناصری که در ابتدا رندر می شوند، زیرمجموعه بسیار کوچکی از کل لیست است و زمانی که کاربر به پیمایش ادامه می دهد، «پنجره» محتوای قابل مشاهده حرکت می کند . این کار هم عملکرد رندر و هم عملکرد اسکرول لیست را بهبود می بخشد.

پنجره محتوا در یک لیست مجازی
جابجایی "پنجره" محتوا در یک لیست مجازی

گره‌های DOM که از «پنجره» خارج می‌شوند، بازیافت می‌شوند یا بلافاصله با اسکرول کردن کاربر در فهرست با عناصر جدیدتر جایگزین می‌شوند. با این کار تعداد تمام عناصر رندر شده مخصوص اندازه پنجره حفظ می شود.

پنجره واکنش

react-window یک کتابخانه کوچک و شخص ثالث است که ایجاد لیست های مجازی در برنامه شما را آسان تر می کند. تعدادی API پایه را ارائه می دهد که می توانند برای انواع مختلف لیست ها و جداول استفاده شوند.

زمان استفاده از لیست های اندازه ثابت

اگر فهرستی طولانی و تک بعدی از اقلام با اندازه یکسان دارید، از مؤلفه FixedSizeList استفاده کنید.

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 height ، width و itemSize را برای کنترل اندازه آیتم های موجود در لیست می پذیرد.
  • تابعی که ردیف ها را رندر می کند به عنوان فرزند به FixedSizeList ارسال می شود. جزئیات مربوط به یک مورد خاص را می توان با آرگومان index ( items[index] ) در دسترس قرار داد.
  • یک پارامتر style نیز به روش رندر ردیف ارسال می شود که باید به عنصر ردیف متصل شود. آیتم‌های فهرست کاملاً با مقادیر ارتفاع و عرض آن‌ها که به صورت خطی تخصیص داده شده است، قرار می‌گیرند و پارامتر style مسئول این است.

مثال Glitch که قبلا در این مقاله نشان داده شد، نمونه ای از یک جزء FixedSizeList را نشان می دهد.

زمان استفاده از لیست های با اندازه متغیر

از مؤلفه VariableSizeList برای ارائه فهرستی از مواردی که اندازه های متفاوتی دارند استفاده کنید. این کامپوننت مانند یک لیست اندازه ثابت کار می کند، اما در عوض به جای یک مقدار خاص، یک تابع برای prop itemSize انتظار دارد.

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;

تعبیه زیر نمونه ای از این کامپوننت را نشان می دهد.

تابع اندازه آیتم که به prop itemSize ارسال می شود، ارتفاع ردیف را در این مثال تصادفی می کند. با این حال، در یک برنامه واقعی، باید منطق واقعی وجود داشته باشد که اندازه هر آیتم را تعریف کند. در حالت ایده آل، این اندازه ها باید بر اساس داده ها محاسبه شوند یا از یک API به دست آیند.

شبکه ها

react-window همچنین از مجازی سازی لیست ها یا شبکه های چند بعدی پشتیبانی می کند. در این زمینه، "پنجره" محتوای قابل مشاهده با حرکت کاربر به صورت افقی و عمودی تغییر می کند.

جابجایی پنجره محتوا در یک شبکه مجازی شده دو بعدی است
جابجایی "پنجره" محتوا در یک شبکه مجازی شده دو بعدی است

به طور مشابه، هر دو مؤلفه FixedSizeGrid و VariableSizeGrid را می توان بسته به اینکه آیا اندازه آیتم های لیست خاص می تواند متفاوت باشد، استفاده می شود.

  • برای FixedSizeGrid ، API تقریباً یکسان است، اما با این واقعیت که ارتفاع، عرض و تعداد آیتم‌ها باید برای ستون‌ها و سطرها نمایش داده شوند.
  • برای VariableSizeGrid ، هم عرض ستون و هم ارتفاع سطر را می توان با انتقال توابع به جای مقادیر به props مربوطه تغییر داد.

برای مشاهده نمونه هایی از شبکه های مجازی سازی شده به مستندات نگاهی بیندازید.

بارگذاری تنبل در اسکرول

بسیاری از وب‌سایت‌ها با صبر کردن برای بارگیری و ارائه آیتم‌ها در یک لیست طولانی تا زمانی که کاربر به پایین پیمایش کند، عملکرد را بهبود می‌بخشند. این تکنیک که معمولاً به عنوان "بارگذاری بی نهایت" نامیده می شود، گره های DOM جدیدی را به لیست اضافه می کند، زیرا کاربر از آستانه مشخصی نزدیک به انتها عبور می کند. اگرچه این بهتر از بارگیری همه موارد در یک لیست به طور همزمان است، اما اگر کاربر از این تعداد ردیف گذشته باشد، همچنان DOM را با هزاران ورودی ردیف پر می کند. این می تواند منجر به یک اندازه DOM بسیار بزرگ شود که با کندتر کردن محاسبات سبک و جهش های DOM شروع به تأثیر بر عملکرد می کند.

نمودار زیر می تواند به خلاصه کردن این موضوع کمک کند:

تفاوت در اسکرول بین لیست معمولی و مجازی
تفاوت در اسکرول بین لیست معمولی و مجازی

بهترین رویکرد برای حل این مشکل، ادامه استفاده از کتابخانه‌ای مانند react-window برای حفظ یک "پنجره" کوچک از عناصر در یک صفحه است، اما همچنین بارگذاری تنبل ورودی‌های جدیدتر هنگام حرکت کاربر به پایین است. یک بسته جداگانه، react-window-infinite-loader ، این کار را با react-window امکان پذیر می کند.

قطعه کد زیر را در نظر بگیرید که نمونه ای از وضعیت را نشان می دهد که در یک مؤلفه App والد مدیریت می شود.

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;

یک متد loadMore به یک ListComponent فرزند ارسال می‌شود که حاوی لیست لودر بی‌نهایت است. این مهم است زیرا لودر بی‌نهایت باید برای بارگیری موارد بیشتر، زمانی که کاربر از نقطه خاصی عبور کرده است، یک تماس برگشتی ایجاد کند.

در اینجا ListComponent که لیست را رندر می کند، می تواند شبیه به این باشد:

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;

در اینجا، مؤلفه FixedSizeList درون InfiniteLoader پیچیده شده است. قطعات تخصیص داده شده به لودر عبارتند از:

  • isItemLoaded : روشی که بررسی می کند آیا یک آیتم خاص بارگذاری شده است یا خیر
  • itemCount : تعداد موارد موجود در لیست (یا مورد انتظار)
  • loadMoreItems : Callback که وعده ای را برمی گرداند که به داده های اضافی لیست حل می شود

یک پروپ رندر برای برگرداندن تابعی استفاده می شود که جزء لیست از آن برای رندر کردن استفاده می کند. هر دو ویژگی onItemsRendered و ref ویژگی هایی هستند که باید به آنها منتقل شوند.

در زیر مثالی از نحوه کار بارگذاری بی نهایت با یک لیست مجازی ارائه شده است.

اسکرول کردن به پایین لیست ممکن است همین احساس را داشته باشد، اما اکنون درخواستی برای بازیابی 10 کاربر از یک API تصادفی کاربر هر بار که به انتهای لیست نزدیک می شوید، ارسال می شود. این همه در حالی انجام می شود که تنها یک "پنجره" از نتایج در یک زمان ارائه می شود.

با بررسی index یک آیتم خاص، بسته به اینکه آیا درخواستی برای ورودی های جدیدتر انجام شده و آیتم هنوز در حال بارگیری است، می توان وضعیت بارگیری متفاوتی را برای یک آیتم نشان داد.

به عنوان مثال:

const Row = ({ index, style }) => {
  const itemLoading = index === items.length;

  if (itemLoading) {
      // return loading state
  } else {
      // return item
  }
};

Overscanning

از آنجایی که موارد موجود در یک لیست مجازی تنها زمانی تغییر می‌کنند که کاربر پیمایش کند، فضای خالی می‌تواند برای مدت کوتاهی چشمک بزند، زیرا ورودی‌های جدیدتر نمایش داده می‌شوند. می‌توانید هر یک از نمونه‌های قبلی را در این راهنما به سرعت پیمایش کنید تا متوجه این موضوع شوید.

برای بهبود تجربه کاربری لیست های مجازی شده، react-window به شما امکان می دهد موارد را با ویژگی overscanCount اسکن کنید. این به شما امکان می‌دهد تا در همه زمان‌ها تعداد آیتم‌های خارج از پنجره قابل مشاهده را تعریف کنید.

<FixedSizeList
  //...
  overscanCount={4}
>
  {...}
</FixedSizeList>

overscanCount برای هر دو مؤلفه FixedSizeList و VariableSizeList کار می کند و مقدار پیش فرض آن 1 است. بسته به بزرگی یک لیست و همچنین اندازه هر مورد، اسکن بیش از حد بیش از یک ورودی می تواند به جلوگیری از فلش محسوس فضای خالی در هنگام اسکرول کردن کاربر کمک کند. با این حال، اسکن بیش از حد ورودی‌ها می‌تواند بر عملکرد تأثیر منفی بگذارد. هدف اصلی استفاده از یک لیست مجازی، به حداقل رساندن تعداد ورودی ها به آنچه کاربر در هر لحظه می تواند ببیند است، بنابراین سعی کنید تعداد موارد بیش از حد اسکن شده را تا حد امکان کم نگه دارید.

برای FixedSizeGrid و VariableSizeGrid ، از ویژگی‌های overscanColumnsCount و overscanRowsCount برای کنترل تعداد ستون‌ها و ردیف‌ها برای اسکن بیش‌ازحد استفاده کنید.

نتیجه گیری

اگر مطمئن نیستید که از کجا مجازی سازی لیست ها و جداول را در برنامه خود شروع کنید، این مراحل را دنبال کنید:

  1. عملکرد رندر و پیمایش را اندازه گیری کنید. این مقاله نشان می‌دهد که چگونه می‌توان از FPS متر در Chrome DevTools برای بررسی میزان کارآمد بودن موارد در فهرست استفاده کرد.
  2. برای هر لیست طولانی یا شبکه‌هایی که بر عملکرد تأثیر می‌گذارند، react-window اضافه کنید.
  3. اگر ویژگی‌های خاصی در react-window پشتیبانی نمی‌شوند، اگر خودتان نمی‌توانید این قابلیت را اضافه کنید، از react-virtualized استفاده کنید.
  4. در صورت نیاز به بارگذاری تنبل آیتم ها در حین حرکت کاربر، لیست مجازی خود را با react-window-infinite-loader بپیچید.
  5. از ویژگی overscanCount برای لیست های خود و از ویژگی های overscanColumnsCount و overscanRowsCount برای شبکه های خود استفاده کنید تا از فلش محتوای خالی جلوگیری کنید. از اسکن بیش از حد ورودی ها خودداری کنید زیرا این کار بر عملکرد تأثیر منفی می گذارد.
،

جداول و لیست های بسیار بزرگ می توانند عملکرد سایت شما را به طور قابل توجهی کاهش دهند. مجازی سازی می تواند کمک کند!

react-window کتابخانه ای است که به لیست های بزرگ اجازه می دهد تا به طور موثر ارائه شوند.

در اینجا نمونه ای از لیستی است که شامل 1000 ردیف است که با react-window ارائه می شود. هر چه سریعتر اسکرول کنید.

چرا این مفید است؟

ممکن است زمان هایی وجود داشته باشد که شما نیاز به نمایش جدول یا لیست بزرگی داشته باشید که دارای ردیف های زیادی است. بارگیری تک تک موارد در چنین لیستی می تواند عملکرد قابل توجهی را تحت تأثیر قرار دهد.

مجازی‌سازی فهرست یا «پنجره‌سازی» مفهومی است که تنها آنچه را که برای کاربر قابل مشاهده است ارائه می‌کند. تعداد عناصری که در ابتدا رندر می شوند، زیرمجموعه بسیار کوچکی از کل لیست است و زمانی که کاربر به پیمایش ادامه می دهد، «پنجره» محتوای قابل مشاهده حرکت می کند . این کار هم عملکرد رندر و هم عملکرد اسکرول لیست را بهبود می بخشد.

پنجره محتوا در یک لیست مجازی
جابجایی "پنجره" محتوا در یک لیست مجازی

گره‌های DOM که از «پنجره» خارج می‌شوند، بازیافت می‌شوند یا بلافاصله با اسکرول کردن کاربر در فهرست با عناصر جدیدتر جایگزین می‌شوند. با این کار تعداد تمام عناصر رندر شده مخصوص اندازه پنجره حفظ می شود.

پنجره واکنش

react-window یک کتابخانه کوچک و شخص ثالث است که ایجاد لیست های مجازی در برنامه شما را آسان تر می کند. تعدادی API پایه را ارائه می دهد که می توانند برای انواع مختلف لیست ها و جداول استفاده شوند.

زمان استفاده از لیست های اندازه ثابت

اگر فهرستی طولانی و تک بعدی از اقلام با اندازه یکسان دارید، از مؤلفه FixedSizeList استفاده کنید.

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 height ، width و itemSize را برای کنترل اندازه آیتم های موجود در لیست می پذیرد.
  • تابعی که ردیف ها را رندر می کند به عنوان فرزند به FixedSizeList ارسال می شود. جزئیات مربوط به یک مورد خاص را می توان با آرگومان index ( items[index] ) در دسترس قرار داد.
  • یک پارامتر style نیز به روش رندر ردیف ارسال می شود که باید به عنصر ردیف متصل شود. آیتم‌های فهرست کاملاً با مقادیر ارتفاع و عرض آن‌ها که به صورت خطی تخصیص داده شده است، قرار می‌گیرند و پارامتر style مسئول این است.

مثال Glitch که قبلا در این مقاله نشان داده شد، نمونه ای از یک جزء FixedSizeList را نشان می دهد.

زمان استفاده از لیست های با اندازه متغیر

از مؤلفه VariableSizeList برای ارائه فهرستی از مواردی که اندازه های متفاوتی دارند استفاده کنید. این کامپوننت مانند یک لیست اندازه ثابت کار می کند، اما در عوض به جای یک مقدار خاص، یک تابع برای prop itemSize انتظار دارد.

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;

تعبیه زیر نمونه ای از این کامپوننت را نشان می دهد.

تابع اندازه آیتم که به prop itemSize ارسال می شود، ارتفاع ردیف را در این مثال تصادفی می کند. با این حال، در یک برنامه واقعی، باید منطق واقعی وجود داشته باشد که اندازه هر آیتم را تعریف کند. در حالت ایده آل، این اندازه ها باید بر اساس داده ها محاسبه شوند یا از یک API به دست آیند.

شبکه ها

react-window همچنین از مجازی سازی لیست ها یا شبکه های چند بعدی پشتیبانی می کند. در این زمینه، "پنجره" محتوای قابل مشاهده با حرکت کاربر به صورت افقی و عمودی تغییر می کند.

جابجایی پنجره محتوا در یک شبکه مجازی شده دو بعدی است
جابجایی "پنجره" محتوا در یک شبکه مجازی شده دو بعدی است

به طور مشابه، هر دو مؤلفه FixedSizeGrid و VariableSizeGrid را می توان بسته به اینکه آیا اندازه آیتم های لیست خاص می تواند متفاوت باشد، استفاده می شود.

  • برای FixedSizeGrid ، API تقریباً یکسان است، اما با این واقعیت که ارتفاع، عرض و تعداد آیتم‌ها باید برای ستون‌ها و سطرها نمایش داده شوند.
  • برای VariableSizeGrid ، هم عرض ستون و هم ارتفاع سطر را می توان با انتقال توابع به جای مقادیر به props مربوطه تغییر داد.

برای مشاهده نمونه هایی از شبکه های مجازی سازی شده به مستندات نگاهی بیندازید.

بارگذاری تنبل در اسکرول

بسیاری از وب‌سایت‌ها با صبر کردن برای بارگیری و ارائه آیتم‌ها در یک لیست طولانی تا زمانی که کاربر به پایین پیمایش کند، عملکرد را بهبود می‌بخشند. این تکنیک که معمولاً به عنوان "بارگذاری بی نهایت" نامیده می شود، گره های DOM جدیدی را به لیست اضافه می کند، زیرا کاربر از آستانه مشخصی نزدیک به انتها عبور می کند. اگرچه این بهتر از بارگیری همه موارد در یک لیست به طور همزمان است، اما اگر کاربر از این تعداد ردیف گذشته باشد، همچنان DOM را با هزاران ورودی ردیف پر می کند. این می تواند منجر به یک اندازه DOM بسیار بزرگ شود که با کندتر کردن محاسبات سبک و جهش های DOM شروع به تأثیر بر عملکرد می کند.

نمودار زیر می تواند به خلاصه کردن این موضوع کمک کند:

تفاوت در اسکرول بین لیست معمولی و مجازی
تفاوت در اسکرول بین لیست معمولی و مجازی

بهترین رویکرد برای حل این مشکل، ادامه استفاده از کتابخانه‌ای مانند react-window برای حفظ یک "پنجره" کوچک از عناصر در یک صفحه است، اما همچنین بارگذاری تنبل ورودی‌های جدیدتر هنگام حرکت کاربر به پایین است. یک بسته جداگانه، react-window-infinite-loader ، این کار را با react-window امکان پذیر می کند.

قطعه کد زیر را در نظر بگیرید که نمونه ای از وضعیت را نشان می دهد که در یک مؤلفه App والد مدیریت می شود.

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;

یک متد loadMore به یک ListComponent فرزند ارسال می‌شود که حاوی لیست لودر بی‌نهایت است. این مهم است زیرا لودر بی‌نهایت باید برای بارگیری موارد بیشتر، زمانی که کاربر از نقطه خاصی عبور کرده است، یک تماس برگشتی ایجاد کند.

در اینجا ListComponent که لیست را رندر می کند، می تواند شبیه به این باشد:

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;

در اینجا، مؤلفه FixedSizeList درون InfiniteLoader پیچیده شده است. قطعات تخصیص داده شده به لودر عبارتند از:

  • isItemLoaded : روشی که بررسی می کند آیا یک آیتم خاص بارگذاری شده است یا خیر
  • itemCount : تعداد موارد موجود در لیست (یا مورد انتظار)
  • loadMoreItems : Callback که وعده ای را برمی گرداند که به داده های اضافی لیست حل می شود

یک پروپ رندر برای برگرداندن تابعی استفاده می شود که جزء لیست از آن برای رندر کردن استفاده می کند. هر دو ویژگی onItemsRendered و ref ویژگی هایی هستند که باید به آنها منتقل شوند.

در زیر مثالی از نحوه کار بارگذاری بی نهایت با یک لیست مجازی ارائه شده است.

اسکرول کردن به پایین لیست ممکن است همین احساس را داشته باشد، اما اکنون درخواستی برای بازیابی 10 کاربر از یک API تصادفی کاربر هر بار که به انتهای لیست نزدیک می شوید، ارسال می شود. این همه در حالی انجام می شود که تنها یک "پنجره" از نتایج در یک زمان ارائه می شود.

با بررسی index یک آیتم خاص، بسته به اینکه آیا درخواستی برای ورودی های جدیدتر انجام شده و آیتم هنوز در حال بارگیری است، می توان وضعیت بارگیری متفاوتی را برای یک آیتم نشان داد.

به عنوان مثال:

const Row = ({ index, style }) => {
  const itemLoading = index === items.length;

  if (itemLoading) {
      // return loading state
  } else {
      // return item
  }
};

Overscanning

از آنجایی که موارد موجود در یک لیست مجازی تنها زمانی تغییر می‌کنند که کاربر پیمایش کند، فضای خالی می‌تواند برای مدت کوتاهی چشمک بزند، زیرا ورودی‌های جدیدتر نمایش داده می‌شوند. می‌توانید هر یک از نمونه‌های قبلی را در این راهنما به سرعت پیمایش کنید تا متوجه این موضوع شوید.

برای بهبود تجربه کاربری لیست های مجازی شده، react-window به شما امکان می دهد موارد را با ویژگی overscanCount اسکن کنید. این به شما امکان می‌دهد تا در همه زمان‌ها تعداد آیتم‌های خارج از پنجره قابل مشاهده را تعریف کنید.

<FixedSizeList
  //...
  overscanCount={4}
>
  {...}
</FixedSizeList>

overscanCount برای هر دو مؤلفه FixedSizeList و VariableSizeList کار می کند و مقدار پیش فرض آن 1 است. بسته به بزرگی یک لیست و همچنین اندازه هر مورد، اسکن بیش از حد بیش از یک ورودی می تواند به جلوگیری از فلش محسوس فضای خالی در هنگام اسکرول کردن کاربر کمک کند. با این حال، اسکن بیش از حد ورودی‌ها می‌تواند بر عملکرد تأثیر منفی بگذارد. هدف اصلی استفاده از یک لیست مجازی، به حداقل رساندن تعداد ورودی ها به آنچه کاربر در هر لحظه می تواند ببیند است، بنابراین سعی کنید تعداد موارد بیش از حد اسکن شده را تا حد امکان کم نگه دارید.

برای FixedSizeGrid و VariableSizeGrid ، از ویژگی‌های overscanColumnsCount و overscanRowsCount برای کنترل تعداد ستون‌ها و ردیف‌ها برای اسکن بیش‌ازحد استفاده کنید.

نتیجه گیری

اگر مطمئن نیستید که از کجا مجازی سازی لیست ها و جداول را در برنامه خود شروع کنید، این مراحل را دنبال کنید:

  1. عملکرد رندر و پیمایش را اندازه گیری کنید. این مقاله نشان می‌دهد که چگونه می‌توان از FPS متر در Chrome DevTools برای بررسی میزان کارآمد بودن موارد در فهرست استفاده کرد.
  2. برای هر لیست طولانی یا شبکه‌هایی که بر عملکرد تأثیر می‌گذارند، react-window اضافه کنید.
  3. اگر ویژگی‌های خاصی در react-window پشتیبانی نمی‌شوند، اگر خودتان نمی‌توانید این قابلیت را اضافه کنید، از react-virtualized استفاده کنید.
  4. در صورت نیاز به بارگذاری تنبل آیتم ها در حین حرکت کاربر، لیست مجازی خود را با react-window-infinite-loader بپیچید.
  5. از ویژگی overscanCount برای لیست های خود و از ویژگی های overscanColumnsCount و overscanRowsCount برای شبکه های خود استفاده کنید تا از فلش محتوای خالی جلوگیری کنید. از اسکن بیش از حد ورودی ها خودداری کنید زیرا این کار بر عملکرد تأثیر منفی می گذارد.
،

جداول و لیست های بسیار بزرگ می توانند عملکرد سایت شما را به طور قابل توجهی کاهش دهند. مجازی سازی می تواند کمک کند!

react-window کتابخانه ای است که به لیست های بزرگ اجازه می دهد تا به طور موثر ارائه شوند.

در اینجا نمونه ای از لیستی است که شامل 1000 ردیف است که با react-window ارائه می شود. هر چه سریعتر اسکرول کنید.

چرا این مفید است؟

ممکن است زمان هایی وجود داشته باشد که شما نیاز به نمایش جدول یا لیست بزرگی داشته باشید که دارای ردیف های زیادی است. بارگیری تک تک موارد در چنین لیستی می تواند عملکرد قابل توجهی را تحت تأثیر قرار دهد.

مجازی‌سازی فهرست یا «پنجره‌سازی» مفهومی است که تنها آنچه را که برای کاربر قابل مشاهده است ارائه می‌کند. تعداد عناصری که در ابتدا رندر می شوند، زیرمجموعه بسیار کوچکی از کل لیست است و زمانی که کاربر به پیمایش ادامه می دهد، «پنجره» محتوای قابل مشاهده حرکت می کند . این کار هم عملکرد رندر و هم عملکرد اسکرول لیست را بهبود می بخشد.

پنجره محتوا در یک لیست مجازی
جابجایی "پنجره" محتوا در یک لیست مجازی

گره‌های DOM که از «پنجره» خارج می‌شوند، بازیافت می‌شوند یا بلافاصله با اسکرول کردن کاربر در فهرست با عناصر جدیدتر جایگزین می‌شوند. با این کار تعداد تمام عناصر رندر شده مخصوص اندازه پنجره حفظ می شود.

پنجره واکنش

react-window یک کتابخانه کوچک و شخص ثالث است که ایجاد لیست های مجازی در برنامه شما را آسان تر می کند. تعدادی API پایه را ارائه می دهد که می توانند برای انواع مختلف لیست ها و جداول استفاده شوند.

زمان استفاده از لیست های اندازه ثابت

اگر فهرستی طولانی و تک بعدی از اقلام با اندازه یکسان دارید، از مؤلفه FixedSizeList استفاده کنید.

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 height ، width و itemSize را برای کنترل اندازه آیتم های موجود در لیست می پذیرد.
  • تابعی که ردیف ها را رندر می کند به عنوان فرزند به FixedSizeList ارسال می شود. جزئیات مربوط به یک مورد خاص را می توان با آرگومان index ( items[index] ) در دسترس قرار داد.
  • یک پارامتر style نیز به روش رندر ردیف ارسال می شود که باید به عنصر ردیف متصل شود. آیتم‌های فهرست کاملاً با مقادیر ارتفاع و عرض آن‌ها که به صورت خطی تخصیص داده شده است، قرار می‌گیرند و پارامتر style مسئول این است.

مثال Glitch که قبلا در این مقاله نشان داده شد، نمونه ای از یک جزء FixedSizeList را نشان می دهد.

زمان استفاده از لیست های با اندازه متغیر

از مؤلفه VariableSizeList برای ارائه فهرستی از مواردی که اندازه های متفاوتی دارند استفاده کنید. این کامپوننت مانند یک لیست اندازه ثابت کار می کند، اما در عوض به جای یک مقدار خاص، یک تابع برای prop itemSize انتظار دارد.

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;

تعبیه زیر نمونه ای از این کامپوننت را نشان می دهد.

تابع اندازه آیتم که به prop itemSize ارسال می شود، ارتفاع ردیف را در این مثال تصادفی می کند. با این حال، در یک برنامه واقعی، باید منطق واقعی وجود داشته باشد که اندازه هر آیتم را تعریف کند. در حالت ایده آل، این اندازه ها باید بر اساس داده ها محاسبه شوند یا از یک API به دست آیند.

شبکه ها

react-window همچنین از مجازی سازی لیست ها یا شبکه های چند بعدی پشتیبانی می کند. در این زمینه، "پنجره" محتوای قابل مشاهده با حرکت کاربر به صورت افقی و عمودی تغییر می کند.

جابجایی پنجره محتوا در یک شبکه مجازی شده دو بعدی است
جابجایی "پنجره" محتوا در یک شبکه مجازی شده دو بعدی است

به طور مشابه، هر دو مؤلفه FixedSizeGrid و VariableSizeGrid را می توان بسته به اینکه آیا اندازه آیتم های لیست خاص می تواند متفاوت باشد، استفاده می شود.

  • برای FixedSizeGrid ، API تقریباً یکسان است، اما با این واقعیت که ارتفاع، عرض و تعداد آیتم‌ها باید برای ستون‌ها و سطرها نمایش داده شوند.
  • برای VariableSizeGrid ، هم عرض ستون و هم ارتفاع سطر را می توان با انتقال توابع به جای مقادیر به props مربوطه تغییر داد.

برای مشاهده نمونه هایی از شبکه های مجازی سازی شده به مستندات نگاهی بیندازید.

بارگذاری تنبل در اسکرول

بسیاری از وب‌سایت‌ها با صبر کردن برای بارگیری و ارائه آیتم‌ها در یک لیست طولانی تا زمانی که کاربر به پایین پیمایش کند، عملکرد را بهبود می‌بخشند. این تکنیک که معمولاً به عنوان "بارگذاری بی نهایت" نامیده می شود، گره های DOM جدیدی را به لیست اضافه می کند، زیرا کاربر از آستانه مشخصی نزدیک به انتها عبور می کند. اگرچه این بهتر از بارگیری همه موارد در یک لیست به طور همزمان است ، اما اگر کاربر گذشته را پیمایش کرده باشد ، هنوز هم با هزاران ورودی ردیف جمع می شود. این می تواند به اندازه DOM بیش از حد بزرگ منجر شود ، که با انجام محاسبات سبک و جهش های DOM کندتر ، عملکرد را تحت تأثیر قرار می دهد.

نمودار زیر ممکن است به خلاصه این موضوع کمک کند:

تفاوت در پیمایش بین یک لیست منظم و مجازی
تفاوت در پیمایش بین یک لیست منظم و مجازی

بهترین روش برای حل این مشکل ، استفاده از کتابخانه ای مانند react-window برای حفظ "پنجره" کوچک عناصر در یک صفحه است ، اما همچنین به عنوان ورودی کاربر ، ورودی های جدیدتر را تنبل می کند. یک بسته جداگانه ، react-window-infinite-loader ، این کار را با react-window امکان پذیر می کند.

کد زیر را در نظر بگیرید که نمونه ای از حالت را نشان می دهد که در یک مؤلفه App والدین مدیریت می شود.

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;

یک روش loadMore به یک ListComponent کودک که شامل لیست لودر بی نهایت است منتقل می شود. این مهم است زیرا لودر بی نهایت پس از اینکه کاربر از یک نقطه خاص عبور کرده است ، نیاز به آتش سوزی برای بارگیری بیشتر موارد دارد.

در اینجا نحوه ListComponent که لیست را ارائه می دهد می تواند به نظر برسد:

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;

در اینجا ، مؤلفه FixedSizeList در InfiniteLoader پیچیده می شود. غرفه های اختصاص داده شده به لودر عبارتند از:

  • isItemLoaded : روشی که بررسی می کند که آیا یک مورد خاص بارگذاری شده است
  • itemCount : تعداد موارد موجود در لیست (یا مورد انتظار)
  • loadMoreItems : پاسخ به تماس که وعده ای را که به داده های اضافی برای لیست برطرف می شود ، برمی گرداند

از Render Prop برای بازگرداندن تابعی که مؤلفه لیست به منظور ارائه آن استفاده می کند ، استفاده می شود. هر دو ویژگی onItemsRendered و ref ویژگی هایی هستند که باید در آن منتقل شوند.

در زیر نمونه ای از چگونگی کار بارگذاری نامتناهی با یک لیست مجازی است.

پیمایش در پایین لیست ممکن است یکسان باشد ، اما اکنون درخواست بازیابی 10 کاربر از یک API کاربر تصادفی هر بار که نزدیک به انتهای لیست می شوید ، بازیابی می شود. این همه کارها انجام می شود در حالی که فقط یک "پنجره" از نتایج را در یک زمان ارائه می دهد.

با بررسی index یک مورد خاص ، بسته به اینکه آیا درخواستی برای ورودی های جدیدتر ایجاد شده است و مورد هنوز در حال بارگیری است ، می توان حالت بارگذاری متفاوتی را برای یک مورد نشان داد.

به عنوان مثال:

const Row = ({ index, style }) => {
  const itemLoading = index === items.length;

  if (itemLoading) {
      // return loading state
  } else {
      // return item
  }
};

بیش از حد

از آنجا که موارد موجود در یک لیست مجازی فقط در هنگام پیمایش کاربر تغییر می کنند ، فضای خالی می تواند به طور خلاصه به عنوان ورودی های جدیدتر در حال نمایش باشد. می توانید به سرعت سعی کنید هر یک از مثالهای قبلی را در این راهنما پیمایش کنید تا به این موضوع توجه کنید.

برای بهبود تجربه کاربر در لیست های مجازی ، react-window به شما امکان می دهد مواردی را با ویژگی overscanCount برطرف کنید. این به شما امکان می دهد تا در هر زمان چند مورد در خارج از "پنجره" قابل مشاهده را تعریف کنید.

<FixedSizeList
  //...
  overscanCount={4}
>
  {...}
</FixedSizeList>

overscanCount برای هر دو مؤلفه FixedSizeList و VariableSizeList کار می کند و دارای مقدار پیش فرض 1. است. بسته به اینکه لیست بزرگ و همچنین اندازه هر مورد بزرگ است ، بیش از یک ورودی بیش از یک ورودی می تواند به جلوگیری از چشم انداز قابل توجه فضای خالی در هنگام پیمایش کاربر کمک کند. با این حال ، حضور بیش از حد تعداد زیادی از ورودی ها می تواند بر عملکرد تأثیر منفی بگذارد. کل نکته استفاده از یک لیست مجازی ، به حداقل رساندن تعداد مطالب مربوط به آنچه کاربر می تواند در هر لحظه مشخص باشد ، به حداقل برسد ، بنابراین سعی کنید تعداد موارد بیش از حد را تا حد ممکن کم نگه دارید.

برای FixedSizeGrid و VariableSizeGrid ، از خواص overscanColumnsCount و overscanRowsCount استفاده کنید تا تعداد ستون ها و ردیف ها را به ترتیب بر روی آن کنترل کنید.

نتیجه گیری

اگر مطمئن نیستید که از کجا لیست ها و جداول مجازی سازی را در برنامه خود شروع کنید ، این مراحل را دنبال کنید:

  1. عملکرد رندر و پیمایش را اندازه گیری کنید. این مقاله نشان می دهد که چگونه می توان از متر FPS در Devtools Chrome استفاده کرد تا چگونگی ارائه موارد کارآمد در یک لیست را کشف کند.
  2. برای هر لیست طولانی یا شبکه هایی که بر عملکرد تأثیر می گذارند ، react-window درج کنید.
  3. اگر ویژگی های خاصی وجود دارد که در react-window پشتیبانی نمی شوند ، اگر نمی توانید خودتان این قابلیت را اضافه کنید ، از react-virtualized استفاده کنید.
  4. اگر نیاز به موارد بارگذاری بار تنبل به عنوان پیمایش کاربر دارید ، لیست مجازی خود را با react-window-infinite-loader بسته بندی کنید.
  5. برای جلوگیری از چشمک زدن به محتوای خالی ، از ویژگی های overscanCount برای لیست های خود و ویژگی های overscanColumnsCount و overscanRowsCount برای شبکه های خود استفاده کنید. تعداد زیادی از ورودی ها را تحت تأثیر قرار ندهید زیرا این امر بر عملکرد تأثیر منفی خواهد گذاشت.