在React中优化大列表的4种方法

列表是大多数Web应用程序不可或缺的一部分,因为它们有助于以更合理的格式显示数据。但是,当应用程序尝试处理列表中的过多数据时,通常会导致性能问题。

在本指南中,我们将概述与巨大的列表相关的一些问题,并逐步解决在React应用程序中克服这些性能挑战的步骤。

先决条件

要继续学习本教程,您需要具备以下条件。

  • 对JavaScript和React的一般理解
  • npm大于v5.2或yarn
  • node版本12或更高

问题

让我们创建一个示例应用程序,以演示当尝试呈现10,000条记录的大型列表时,应用程序的性能和DOM树会发生什么。

启动您的终端并粘贴下面的代码以创建一个React应用程序。

npx create-react-app render-list

运行以下代码以安装Faker库,我们将使用该库来生成要在我们的应用程序中使用的随机数据。

npm i faker

接下来,转到目录中的App组件,src然后输入以下代码。

import React from 'react';
import faker from 'faker'
import './App.css';

const data = new Array(10000).fill().map((value, index) => ({ id: index, title: faker.lorem.words(5), body: faker.lorem.sentences(4) }))

function App() {
  return (
    <div>
      {data.map(((item) => (
        <div key={item.id} className="post">
          <h3>{item.title} - {item.id}</h3>
          <p>{item.body}</p>
        </div>
      )))}
    </div>
  );
}
export default App;             

转到文件并在下面添加代码行,以向列表中添加一些样式。App.css

.post{
  background-color: #eee;
  margin: 2rem;
  padding: 1rem;
}
.pagination{
  margin: 1rem auto;
  list-style: none;
  display: flex;
  justify-content: space-evenly;
  width: 50%;
}
.active{
  border: 1px solid black;
  border-radius: 100%;
  padding: 0 3px;
  outline: none;
} 

上面的代码呈现了10,000条记录的列表。

在浏览器中启动React应用程序并打开控制台。


渲染列表示例

页面加载后,您会注意到呈现列表需要花费时间。滚动时还有明显的滞后。

以下是解决React应用中与列表相关的性能问题的四种方法。

1.分页

分页使您可以在页面中呈现数据,而不是一次呈现所有信息。这样,您基本上可以控制页面上显示的数据量,因此您不必对DOM树施加过多的压力。

React中的大多数UI库都带有分页组件,但是如果您想快速实现分页而不需要安装UI库,则可能需要检出react-paginate。该库呈现了一个分页组件,该组件接受一些props,可帮助您浏览数据。

要安装该库,请在终端中运行以下代码。

npm i react-paginate

安装后,您可以修改App组件以对数据进行分页而不是立即渲染。将下面的代码粘贴到您的App组件中。

import React, { useState, useEffect } from 'react';
import ReactPaginate from 'react-paginate';
import faker from 'faker'
import './App.css';

function App() {
  const [pagination, setPagination] = useState({
    data: new Array(1000).fill().map((value, index) => (({
      id: index,
      title: faker.lorem.words(5),
      body: faker.lorem.sentences(8)
    }))),
    offset: 0,
    numberPerPage: 10,
    pageCount: 0,
    currentData: []
  });
  useEffect(() => {
    setPagination((prevState) => ({
      ...prevState,
      pageCount: prevState.data.length / prevState.numberPerPage,
      currentData: prevState.data.slice(pagination.offset, pagination.offset + pagination.numberPerPage)
    }))
  }, [pagination.numberPerPage, pagination.offset])
  const handlePageClick = event => {
    const selected = event.selected;
    const offset = selected * pagination.numberPerPage
    setPagination({ ...pagination, offset })
  }
  return (
    <div>
      {pagination.currentData && pagination.currentData.map(((item, index) => (
        <div key={item.id} className="post">
          <h3>{`${item.title} - ${item.id}`}</h3>
          <p>{item.body}</p>
        </div>
      )))
      }
      <ReactPaginate
        previousLabel={'previous'}
        nextLabel={'next'}
        breakLabel={'...'}
        pageCount={pagination.pageCount}
        marginPagesDisplayed={2}
        pageRangeDisplayed={5}
        onPageChange={handlePageClick}
        containerClassName={'pagination'}
        activeClassName={'active'}
      />
    </div>
  );
}
export default App;                

在此示例中,我们以分页状态存储负责分页的详细信息。我们只渲染当前数据,而不是一次渲染数据,而是通过基于当前偏移量和要在页面上显示的记录数对主数据进行切片来获得当前数据。

ReactPaginate组件接受事件处理程序作为props,每当页面更改时都会调用该事件处理程序。事件处理程序计算当前偏移量,然后将其用于计算页面加载时要显示的当前数据。

以下是添加了分页功能后该应用程序外观的屏幕截图。


列表以react-paginate分页

2.无限滚动

渲染大量数据的另一种方法是无限滚动。无限滚动涉及在向下滚动列表时将数据追加到页面的末尾。最初加载页面时,仅加载一部分数据。向下滚动页面时,将附加更多数据。

有几种方法可以在React中实现无限滚动。就个人而言,我更喜欢使用react-infinite-scroll-component。要安装它,请在终端中运行以下代码。

npm i react-infinite-scroll-component 

打开您的App组件并粘贴以下内容。

import React, { useState } from 'react';
import faker from 'faker'
import InfiniteScroll from 'react-infinite-scroll-component';
import './App.css';

function App() {
  const data = new Array(1000).fill().map((value, id) => (({
    id: id,
    title: faker.lorem.words(5),
    body: faker.lorem.sentences(8)
  })))

  const [count, setCount] = useState({
    prev: 0,
    next: 10
  })
  const [hasMore, setHasMore] = useState(true);
  const [current, setCurrent] = useState(data.slice(count.prev, count.next))
  const getMoreData = () => {
    if (current.length === data.length) {
      setHasMore(false);
      return;
    }
    setTimeout(() => {
      setCurrent(current.concat(data.slice(count.prev + 10, count.next + 10)))
    }, 2000)
    setCount((prevState) => ({ prev: prevState.prev + 10, next: prevState.next + 10 }))
  }

  return (
    <InfiniteScroll
      dataLength={current.length}
      next={getMoreData}
      hasMore={hasMore}
      loader={<h4>Loading...</h4>}
    >
      <div>
        {current && current.map(((item, index) => (
          <div key={index} className="post">
            <h3>{`${item.title}-${item.id}`}</h3>
            <p>{item.body}</p>
          </div>
        )))
        }
      </div>
    </InfiniteScroll>
  );
}
export default App;

基本上,这里发生的是每当用户滚动到页面末尾时,它都会检查该hasMore属性是否为false。如果不是,它将附加更多数据到页面。它会继续将数据追加到页面的末尾,直到该hasMore属性变为false为止。

3。 react-virtualized

react-virtualized专为呈现大型列表和表格数据而设计。它使用类似于无限滚动的技术,称为窗口化。使用窗口时,只有列表的可见部分才会呈现到屏幕上。

与上述解决方案相比的一个优势是其丰富的有用组件,其中包括:react-virtualized

  • Collection
  • Grid
  • List
  • Masonryf
  • Table

要安装 ,请启动您的终端并运行以下命令。react-virtualized

npm i react-virtualized

转到您的App组件,然后粘贴下面的代码。

import React from 'react';
import faker from 'faker'
import { List } from "react-virtualized";
import './App.css';

function App() {
  const data = new Array(1000).fill().map((value, id) => (({
    id: id,
    title: faker.lorem.words(5),
    body: faker.lorem.sentences(8)
  })))

  const renderRow = ({ index, key, style }) => (
   <div>
    <div key={key} style={style} className="post">
      <h3>{`${data[index].title}-${data[index].id}`}</h3>
      <p>{data[index].body}</p>
    </div>
   </div>
  )
  return (
    <List
      width={1200}
      height={700}
      rowRenderer={renderRow}
      rowCount={data.length}
      rowHeight={120}
    />
  );
}
export default App;                              

List组件采用widthheightprops来设置窗口的尺寸。它还采用rowHeightprop,它代表列表中每个项目的高度rowCount,而代表数组的长度。rowRenderer采用负责呈现每一行的功能。

react-virtualized带有许多其他处理大列表的选项

4, react-window

react-window是用于在React中有效呈现大型列表的一组组件。该库的完整重写react-virtualized旨在解决与大小和速度有关的缺点。react-window还涵盖了比react-virtualized更多的案例。

通过在终端中运行以下代码进行安装react-window

npm i react-window

转到您的App组件,然后将代码替换为下面的代码。

import React from 'react';
import faker from 'faker'
import { FixedSizeList as List } from "react-window";
import './App.css';

function App() {
  const data = new Array(1000).fill().map((value, id) => (({
    id: id,
    title: faker.lorem.words(5),
    body: faker.lorem.sentences(8)
  })))

  const Row = ({ index, key, style }) => (
   <div>
    <div key={key} style={style} className="post">
      <h3>{`${data[index].title}-${data[index].id}`}</h3>
      <p>{data[index].body}</p>
    </div>
   </div>
  )
  return (
    <List
      width={1400}
      height={700}
      itemCount={data.length}
      itemSize={120}
    >
      {Row}
    </List>
  );
}
export default App;                              

该代码与react-virtualized的代码非常相似。我们使用了一个List组件,该组件接受一组定义列表的props,并传入一个Row组件函数,该函数负责呈现列表中的每一行。

结论

处理大型列表时,重要的是不要一次渲染所有数据,以避免DOM树超载。改善性能的最佳方法取决于您的用例。如果您希望将所有数据都放在一个位置,则无限滚动或开窗技术将是您的最佳选择。否则,您可能希望使用分页解决方案,该解决方案可将数据分为不同的页面。

参考

4 ways to render large lists in React

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容