【问题标题】:Next.js getServerSideProps loading stateNext.js getServerSideProps 加载状态
【发布时间】:2021-11-14 16:41:40
【问题描述】:

有没有一种方法可以让我们拥有类似于在client-side 上获取数据时的加载状态?

我想要一个加载状态的原因是有一个加载骨架之类的东西,例如react-loading-skeleton

在客户端我们可以这样做:

import useSWR from 'swr'

const fetcher = (url) => fetch(url).then((res) => res.json())

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

但对于 SSR (getServerSideProps),我不知道这是否可行,例如我们可以有一个加载状态吗?

function AllPostsPage(props) {
  const router = useRouter();
  const { posts } = props;

  function findPostsHandler(year, month) {
    const fullPath = `/posts/${year}/${month}`;

    router.push(fullPath);
  }

  if (!data) return <div>loading...</div>; // Would not work with SSR

  return (
    <Fragment>
      <PostsSearch onSearch={findPostsHandler} />
      <PosttList items={posts} />
    </Fragment>
  );
}

export async function getServerSideProps() {
  const posts = await getAllPosts();

  return {
    props: {
      posts: posts,
    },
  };
}

export default AllPostsPage;

最近 Next.js 发布了getServerSideProps should support props value as Promise https://github.com/vercel/next.js/pull/28607 有了它,我们可以做出承诺,但不确定如何实现它并拥有加载状态,或者这是否可以实现。他们的例子表明:

export async function getServerSideProps() {
  return {
    props: (async function () {
      return {
        text: 'promise value',
      }
    })(),
  }
}

【问题讨论】:

  • 这能回答你的问题吗? nextjs getServerSideProps show loading
  • 不是真的,因为那是基于_app.js。我希望它在页面组件级别。目前唯一/最好的解决方案是在客户端进行。使用getServerSideProps,目前获取加载状态非常麻烦。

标签: javascript next.js getserversideprops


【解决方案1】:

您可以在 _app.js 上设置加载状态

import Router from "next/router";

export default function App({ Component, pageProps }) {
  const [loading, setLoading] = React.useState(false);
  React.useEffect(() => {
    const start = () => {
      console.log("start");
      setLoading(true);
    };
    const end = () => {
      console.log("findished");
      setLoading(false);
    };
    Router.events.on("routeChangeStart", start);
    Router.events.on("routeChangeComplete", end);
    Router.events.on("routeChangeError", end);
    return () => {
      Router.events.off("routeChangeStart", start);
      Router.events.off("routeChangeComplete", end);
      Router.events.off("routeChangeError", end);
    };
  }, []);
  return (
    <>
      {loading ? (
        <h1>Loading...</h1>
      ) : (
        <Component {...pageProps} />
      )}
    </>
  );
}

【讨论】:

    【解决方案2】:

    我还没有尝试过这个功能,但理论上我认为它应该可以工作。如果您只想让客户端通过服务器道具访问承诺,请尝试如下。基本上,您的 props 是一个异步 lambda 函数,因此您可以做任何需要的工作,例如在其中获取数据等,因此客户端应该以 Promise 的形式访问 props 并等待它。

        export async function getServerSideProps() {
      return {
        props: (async function () {
               const posts = await getAllPosts();
          return {
            posts: posts,
          }
        })(),
      }
    }
    
    //then on client-side you can do the following or similar to set loading state
    
    function MyComponent(props) {
    
     const [isLoading, setIsLoading] = useState(false);
     const [posts, setPosts] = useState({});
    
     useEffect(async () => {
       setIsLoading(true);
       const tempPosts = await props?.posts;
       setPosts(posts);
       setIsLoading(false);
    }, [])
    
    return (
     {isLoading && <div>loading...</div>}
    );
    
    }
    
    export default MyComponent;
    
    

    【讨论】:

    • 是的,这是有道理的。我的问题/问题是我如何实现加载状态,例如if (!data) return &lt;div&gt;loading...&lt;/div&gt;;
    • 更新了以前的答案以包括客户端
    【解决方案3】:

    您可以修改 _app.js 组件以显示 Loading 组件,而 getServerSideProps 正在像 fetch 一样执行异步工作,如此处 https://stackoverflow.com/a/60756105/13824894 所示。这将适用于您应用中的每个页面转换。

    您仍然可以独立使用您的加载逻辑客户端。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-26
      • 2021-12-31
      • 2020-10-14
      • 2021-11-11
      • 1970-01-01
      • 2021-01-14
      相关资源
      最近更新 更多