我的自定义useScrollPosition钩子在Next JS中不工作,当我试图获取下一页结果时

4c8rllxm  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(129)

详情

我正在使用tRPC和useInfiniteQuery在一个nextjs twitter克隆中创建无限滚动效果。我相信这工作正常。我已经测试过了,我可以获取下一页的tweet。
不过我做了一个自定义钩子,它会检查用户当前位置在页面上的位置,状态看起来根本没有更新。它会在页面加载时获取滚动位置,仅此而已。

Feed组件代码

// Dependencies
import Link from 'next/link';
import { useState, useEffect } from 'react';

// API
import { api } from '~/utils/api';

// Components
import { LoadingSpinner } from '~/components/LoadingSpinner';
import { TweetView } from '~/components/TweetView';

function useScrollPosition() {
  const [scrollPosition, setScrollPosition] = useState(0);

  const handleScroll = () => {
    const height =
      document.documentElement.scrollHeight -
      document.documentElement.clientHeight;
    const winScroll =
      document.body.scrollTop || document.documentElement.scrollTop;

    const scrolled = (winScroll / height) * 100;
    setScrollPosition(scrolled);
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);

    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

  return scrollPosition;
}

// Feed Limit
const LIMIT = 10;

export const Feed = () => {
  const {
    data,
    isLoading: tweetsLoading,
    hasNextPage,
    fetchNextPage,
    isFetching,
  } = api.tweet.getAll.useInfiniteQuery(
    {
      limit: LIMIT,
    },
    {
      getNextPageParam: (lastPage) => lastPage.nextCursor,
    }
  );

  const scrollPosition = useScrollPosition();

  const tweets = data?.pages.flatMap((page) => page.tweetsWithUsers) ?? [];
  console.log(scrollPosition);

  useEffect(() => {
    const nextTweetPage = async () => {
      // Get the next page of data if the scroll position is at x
      if (scrollPosition > 90 && hasNextPage && !isFetching) {
        await fetchNextPage();
      }
    };
    nextTweetPage().catch((e) => console.log(e));
  }, [scrollPosition, hasNextPage, isFetching, fetchNextPage]);

  if (tweetsLoading) {
    return (
      <div className="mt-4 flex h-screen items-center justify-center">
        <LoadingSpinner size={40} />
      </div>
    );
  }

  if (!data) {
    return (
      <div className="flex flex-col items-center justify-center gap-6 p-6 text-center">
        <h3>{`Hmmm... Something went wrong getting these twoots, try refreshing?`}</h3>
        <Link
          href="/"
          className="rounded-full bg-bright-pink py-2.5 px-3.5 text-base font-bold text-white shadow-sm hover:bg-pink-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bright-pink"
        >
          Home
        </Link>
      </div>
    );
  }

  return (
    <div className="h-full">
      {tweets.map((fullTweet) => (
        <TweetView
          tweetData={{ ...fullTweet }}
          key={fullTweet.tweet.id}
          input={{ limit: LIMIT }}
        />
      ))}
    </div>
  );
};

我做了什么

我试过寻找其他的解决方案,比如useCallback,也试过其他类似的堆栈溢出问题,但没有一个解决方案是有效的。
被难倒在这一段时间,我不能前进的项目没有这个工作。

zujrkrfu

zujrkrfu1#

当前Hacky解决方案

我今天需要让这个工作现实。我使用了一个名为react-intersection-observer的包。创建了一个div,它将呈现在提要的底部。一旦带有交叉引用的div进入视图,下一页将被获取。
我有点恼火,我不能让挂钩工作,无论什么原因。但这做的工作刚刚好。
这是代码,如果其他人正在挣扎。

Feed组件

// Dependencies
import Link from 'next/link';
import { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';

// API
import { api } from '~/utils/api';

// Components
import { LoadingSpinner } from '~/components/LoadingSpinner';
import { TweetView } from '~/components/TweetView';

// Feed Limit
const LIMIT = 10;

export const Feed = () => {
  const {
    data,
    isLoading: tweetsLoading,
    hasNextPage,
    fetchNextPage,
    isFetching,
  } = api.tweet.getAll.useInfiniteQuery(
    {
      limit: LIMIT,
    },
    {
      getNextPageParam: (lastPage) => lastPage.nextCursor,
    }
  );
  const { ref, inView } = useInView({ threshold: 0 });

  const tweets = data?.pages.flatMap((page) => page.tweetsWithUsers) ?? [];

  useEffect(() => {
    const nextTweetPage = async () => {
      // Get the next page of data if the intersection comes into view
      if (inView && hasNextPage && !isFetching) {
        await fetchNextPage();
      }
    };
    nextTweetPage().catch((e) => console.log(e));
  }, [inView, hasNextPage, isFetching, fetchNextPage]);

  if (tweetsLoading) {
    return (
      <div className="mt-4 flex h-screen items-center justify-center">
        <LoadingSpinner size={40} />
      </div>
    );
  }

  if (!data) {
    return (
      <div className="flex flex-col items-center justify-center gap-6 p-6 text-center">
        <h3>{`Hmmm... Something went wrong getting these twoots, try refreshing?`}</h3>
        <Link
          href="/"
          className="rounded-full bg-bright-pink py-2.5 px-3.5 text-base font-bold text-white shadow-sm hover:bg-pink-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bright-pink"
        >
          Home
        </Link>
      </div>
    );
  }

  return (
    <>
      <div className="h-full">
        {tweets.map((fullTweet) => (
          <TweetView
            tweetData={{ ...fullTweet }}
            key={fullTweet.tweet.id}
            input={{ limit: LIMIT }}
          />
        ))}
      </div>
      <div ref={ref}></div>
      {isFetching && (
        <div className="flex h-auto w-full items-center justify-center p-4">
          <LoadingSpinner size={40} />
        </div>
      )}
    </>
  );
};

相关问题