用React查询懒惰加载长列表 的详细指南

2,263 阅读3分钟

在这篇文章中,我们将优化我们的列表组件,它显示数据。一旦我们通过它,你将学会如何提高你的应用程序的性能,使你的应用程序的体验更好。不多说了,让我们开始吧!🤓

为什么要偷懒加载你的数据?🙋🏽

想象一下,你的应用程序有一个屏幕,有三个列表组件正在渲染,每个列表都有成千上万的记录,正在用REST从你的服务器获取。现在你可以一次性获得所有的数据,但这意味着你与服务器的通信可能需要时间,因为它必须带来大量的数据,这浪费了用户的时间和你的应用程序的性能。如何解决这个问题呢?

  • 给你的用户分页,这样他们就可以访问他们自己选择的页面。
  • 一旦用户到达列表的末尾,就触发下一批的数据

现在,这两种解决方案都是有效的,因为它们服务于不同的目的,并根据需求来使用,但在这个解决方案中,我们要做的是一旦用户到达列表的末尾就自动获取下一批数据。

无限滚动React

我们将使用一个包来支持无限滚动的列表,如果你喜欢,可以自己制作一个:

npm i react-infinite-scroll-component

我们遵循我们的一个关于react query的教程的代码基础。按照该教程中的分层架构,我们将在我们的API层中做一些改变

const fetchPlanets = async ({ pageParam = 1 }) => {  return axiosInstance({    url: `planets/?page=${pageParam}`,    method: "GET",  }).then(({ data }) => {    const response = {      results: data?.results,      next: data.next === null ? undefined : pageParam + 1,    };    return response;  });};

我们添加了默认值为1的pageParams,我们的服务器原始响应看起来是这样的

{
	"count": 60,
	"next": "https://swapi.dev/api/planets/?page=2",
	"previous": null,
	"results": [
		{
			"name": "Tatooine",
			"rotation_period": "23",
			"orbital_period": "304",
			"diameter": "10465",
			"climate": "arid",
			"gravity": "1 standard",
			"terrain": "desert",
			"surface_water": "1",
			"population": "200000",
            ...
		},
	]
}

在我们的自定义钩子上,我们将用react query的useQuery替换useInfiniteQuery,这将帮助我们实现懒惰加载,并再次以最小的代码实现。😎

const usePlanets = () => {
  return useInfiniteQuery(["get-planets"], fetchPlanets, {
    getNextPageParam: (lastPage) => lastPage.next,
    select: (data) => data,
  });
};

我们在这里使用了getNextPageParam选项,这样我们就可以使用react query来检查下一页的内容,现在我们已经完成了自定义钩子,让我们进入实际的组件

const CustomComponent = () => {
  const { data: planets, isLoading, hasNextPage } =
    usePlanets();
  const [dataLength, setDataLength] = useState(0);

  useEffect(() => {
    if (!!planets && !!planets?.pages && planets?.results) {
      setDataLength(
        planets.pages.reduce((counter, page) => {
          return counter + page.results.length;
        }, 0)
      );
    }
  }, [planets]);

  return (
    <InfiniteScroll
      dataLength={dataLength}
      next={fetchNextPage}
      hasMore={!!hasNextPage}
      loader={<div>Automatically fetching next page...</div>}
    >
      {planets?.pages?.map((pageResult, i) => {
        return (
          <React.Fragment key={i}>
            {pageResult.results.map((planet) => (
              <Planet
                key={planet.id}
                planet={planet}
              />
            ))}
          </React.Fragment>
        );
      })}
    </InfiniteScroll>
  )
}

export default CustomComponent

在这里,我们使用了之前安装的InfiniteScroll组件来延迟加载我们的列表,然后我们开始将我们的数据映射为组件的子节点,并从react query中提供next,hasMoreloader

关键时刻🤓

总结

好吧,这篇很长,有很多代码😮‍💨 ,但是我们做到了,给你自己一个饼干,你做得很好。我们学会了如何用react query的懒惰加载使我们的应用程序的体验变得无缝。当我们的行星列表在无限滚动的帮助下被懒惰地获取时。下一次见。在那之前,保重