Nextjs getInitialProps阻止了客户端的页面渲染?

g52tjvyc  于 2023-06-22  发布在  其他
关注(0)|答案(2)|浏览(129)

由于我想添加SSR到我即将到来的项目,以提高SEO,我想尝试下一个。我想要的是,只使用SSR的初始页面,在该网站的导航将客户端渲染其余。我看到getInitialProps在这种情况下最适合,相应的文档。
据我所知,getInitialProps在服务器端运行,用于初始页面渲染,在浏览器中使用next/link导航时运行。我发现的问题是getInitialProps似乎会阻止页面呈现。(即在getInitialProps完成后页面更改/渲染)

import axios from 'axios'

function Posts(props) {
  return (
    <div>
      <div>Posts:</div>
      <div>
        {JSON.stringify(props)}
      </div>
    </div>
  )
}

Posts.getInitialProps = async (context) => {
  const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
  // Wait longer to see the effect
  // await (new Promise((resolve) => {
  //   setTimeout(resolve, 5000)
  // }))
  return {
    props: {
      posts: response.data
    }
  }
}

export default Posts;

我如何才能像纯React一样,先渲染jsx,然后再填充props?(执行JSON.stringify(props)可能首先被忽略)

此外,在下一个9.3中,团队引入了getServerSideProps,推荐使用getInitialProps。当它们与getServerSideProps在服务器上运行时不相同时,它们如何具有可比性?

f0brbegy

f0brbegy1#

根据您的注解,您希望在初始页面加载时在服务器上执行获取。但是,如果在页面之间导航,您不希望在等待getInitialProps返回时呈现阻塞。
一个解决方案是检查您是否在服务器上,并在getInitialProps中执行fetch。如果是在客户端上,不要在getInitialProps中进行获取,而是在渲染方法中使用useEffect进行获取。

import {useEffect} from 'react'
import axios from 'axios'

const isServer = () => typeof window === 'undefined'

const getPosts = () => {
  return axios.get('https://jsonplaceholder.typicode.com/posts')
    .then(response => response.data)
}

function Posts({posts}) {
  const [renderPosts, setRenderPosts] = useState(posts)

  useEffect(() => {
    if(posts === null) {
      getPosts()
        .then(setRenderPosts)
    }
  }, [])

  return (
    <div>
      <div>Posts:</div>
      <div>
        {JSON.stringify(renderPosts)}
      </div>
    </div>
  )
}

Posts.getInitialProps = async (context) => {
  if(isServer()) {
    return {
      posts: await getPosts(),
    }
  }
  else {
    return {
      posts: null,
    }
  }
}

export default Posts

顺便说一下,您可能会在这里使用getServerSideProps,因为只有在服务器上呈现时才会调用它。但是,当使用getServerSideProps呈现页面时,它实际上会调用服务器从getServerSideProps获取数据,即使您使用next/link进行导航。关于Next.js 9.3 blog post
当在浏览器中使用next/link而不是执行getServerSideProps在页面之间导航时,Next.js将对服务器进行获取,这将返回调用getServerSideProps的结果。
这仍然会导致您希望避免的阻塞问题。
最后一点,这可能不是一个惯用的解决方案。可能会有更“标准”的解决方案。我就是找不到。您可能还可以使用页面组件的 Package 器,以更一致的方式完成所有这些工作。如果你经常使用这种模式,我建议你这样做。

oxf4rvwz

oxf4rvwz2#

我实现了一个不同于@Cully的解决方案。
我不想使用getInitialProps作为it's considered legacy
我们可以使用这个帮助器来知道我们是在第一次初始加载时,还是在客户端导航之后。

const isFirstServerCall = context.req?.url?.indexOf('/_next/data/') === -1;

所以我要做的是:
创建一个ssr.ts文件如下:

import { DehydratedState } from '@tanstack/react-query';
import { GetServerSideProps } from 'next';

type ServerSideResponse = {
  dehydratedState?: DehydratedState;
};

export const onlyOnFirstServerCall = (
  getServerSidePropsFunc: GetServerSideProps<ServerSideResponse>
): GetServerSideProps<ServerSideResponse> => {
  return async (context: any) => {
    const isFirstServerCall = context.req?.url?.indexOf('/_next/data/') === -1;
    if (!isFirstServerCall) {
      return {
        props: {}
      };
    } else {
      return getServerSidePropsFunc(context);
    }
  };
};

在您的页面上,此函数将像HoC一样使用:

export const getServerSideProps = onlyOnFirstServerCall(async (ctx: any) => {
  const queryObject = ctx.query;
  ...what you do normally
});

因此,您可以选择是否启用它。

相关问题