使用RTK(Redux-Toolkit)无限滚动

发布于 2025-02-02 14:56:43 字数 2687 浏览 3 评论 0 原文

我正在努力通过光标分页来实现无限滚动的全部支持,增加了新的元素和删除。我使用了GitHub讨论中的一个很好的例子根据我的要求,很少进行调整。这是我实现 useinfinitequery

export function useInfiniteQuery<
  ListOptions,
  ResourceType,
  ResultType extends IList<ResourceType> = IList<ResourceType>,
  Endpoint extends QueryHooks<
    QueryDefinition<any, any, any, ResultType, any>
  > = QueryHooks<QueryDefinition<any, any, any, ResultType, any>>,
>(
  endpoint: Endpoint,
  {
    options,
    getNextPageParam,
    select = defaultSelect,
    inverseAppend = false,
  }: UseInfiniteQueryOptions<ListOptions, ResultType, ResourceType>,
) {
  const nextPageRef = useRef<string | undefined>(undefined);
  const resetRef = useRef(true);
  const [pages, setPages] = useState<ResourceType[] | undefined>(undefined);
  const [trigger, result] = endpoint.useLazyQuery();

  const next = useCallback(() => {
    if (nextPageRef.current !== undefined) {
      trigger(
        { options: { ...options, page_after: nextPageRef.current } },
        true,
      );
    }
  }, [trigger, options]);

  useEffect(() => {
    resetRef.current = true;
    trigger({ options }, true);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, Object.values(options));

  useEffect(() => {
    if (!result.isSuccess) {
      return;
    }
    nextPageRef.current = getNextPageParam(result.data);
    if (resetRef.current) {
      resetRef.current = false;
      setPages(select(result.data));
    } else {
      setPages((pages) =>
        inverseAppend
          ? select(result.data).concat(pages ?? [])
          : (pages ?? []).concat(select(result.data)),
      );
    }
  }, [result.data, inverseAppend, getNextPageParam, select, result.isSuccess]);

  return {
    ...result,
    data: pages,
    isLoading: result.isFetching && pages === undefined,
    hasMore: nextPageRef.current !== undefined,
    next,
  };
}

这个示例在分页方面非常有用,但是当我尝试添加新元素时,问题。我无法区分新元素是从新的分页批处理到达的,或者我打电话给突变和无效的标签(在这种情况下为RTK Refetch Refetch当前订阅和update result.data 我'm在第二使用中聆听。

我需要以某种方式确定何时需要附加新的到达数据(如果下一个分页)或完全替换(如果何时调用突变并需要重置光标并滚动到顶部/底部)。

我的调用突变并获取放置在不同组件中的数据。我试图在调用突变并需要重置数据时使用 fixed cachekey 进行侦听,但是当我需要在不同的地方重复使用突变时,我很快就会面临很多重复和问题,但是请保持相同修复了缓存键。

有人有一个想法如何完成?也许,我需要使用 useInfiniteQuery 实现或为当前实现提供一些修复程序。但是我不知道处理这种情况。谢谢!

I'm struggling to implement full support of infinite scroll with cursor pagination, adding new elements and removing. I have used great example from github discussion https://github.com/reduxjs/redux-toolkit/discussions/1163#discussioncomment-876186 with few adjustments based on my requirements. Here is my implementation of useInfiniteQuery.

export function useInfiniteQuery<
  ListOptions,
  ResourceType,
  ResultType extends IList<ResourceType> = IList<ResourceType>,
  Endpoint extends QueryHooks<
    QueryDefinition<any, any, any, ResultType, any>
  > = QueryHooks<QueryDefinition<any, any, any, ResultType, any>>,
>(
  endpoint: Endpoint,
  {
    options,
    getNextPageParam,
    select = defaultSelect,
    inverseAppend = false,
  }: UseInfiniteQueryOptions<ListOptions, ResultType, ResourceType>,
) {
  const nextPageRef = useRef<string | undefined>(undefined);
  const resetRef = useRef(true);
  const [pages, setPages] = useState<ResourceType[] | undefined>(undefined);
  const [trigger, result] = endpoint.useLazyQuery();

  const next = useCallback(() => {
    if (nextPageRef.current !== undefined) {
      trigger(
        { options: { ...options, page_after: nextPageRef.current } },
        true,
      );
    }
  }, [trigger, options]);

  useEffect(() => {
    resetRef.current = true;
    trigger({ options }, true);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, Object.values(options));

  useEffect(() => {
    if (!result.isSuccess) {
      return;
    }
    nextPageRef.current = getNextPageParam(result.data);
    if (resetRef.current) {
      resetRef.current = false;
      setPages(select(result.data));
    } else {
      setPages((pages) =>
        inverseAppend
          ? select(result.data).concat(pages ?? [])
          : (pages ?? []).concat(select(result.data)),
      );
    }
  }, [result.data, inverseAppend, getNextPageParam, select, result.isSuccess]);

  return {
    ...result,
    data: pages,
    isLoading: result.isFetching && pages === undefined,
    hasMore: nextPageRef.current !== undefined,
    next,
  };
}

This example works great with pagination, but the problem when I'm trying to add new elements. I can't distinguish are new elements arrived from new pagination batch or when I called mutation and invalidated tag (in this case RTK refetch current subscriptions and update result.data which I'm listening in second useEffect).

I need to somehow to identify when I need to append new arrived data (in case of next pagination) or replace fully (in case when mutation was called and needs to reset cursor and scroll to top/bottom).

My calling mutation and fetching the data placed in different components. I tried to use fixedCacheKey to listening when mutation was called and needs to reset data, but I very quickly faced with a lot of duplication and problem when I need to reuse mutation in different places, but keep the same fixed cache key.

Someone has an idea how to accomplish it? Perhaps, I need to take another direction with useInfiniteQuery implementation or provide some fixes to current implementation. But I have no idea to handle this situation. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文