如何仅在 NextJS 站点构建期间使用 getInitialProps?

How can I use getInitialProps only during the NextJS site build?

当使用 NextJS 构建静态站点时,我希望 getInitialProps 方法仅在构建步骤期间触发,而不是在客户端触发。

在构建步骤中,NextJS 运行在每个组件呈现HTML之前的getInitialProps method用于生成页面的静态HTML。在客户端,NextJS 还在页面组件呈现之前 运行s 这个方法,以便 return 组件的必要道具。因此,大请求可能会延迟客户端的第一次绘制,因为这是一个阻塞请求。

// example usage of API call in getInitialProps
import fetch from 'isomorphic-unfetch'

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async ({ req }) => {
  const res = await fetch('https://api.github.com/repos/zeit/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

我不愿意将我缓慢的 API 请求移动到 componentDidMount 以避免阻塞请求,因为我想在构建步骤中使用数据 returned 来填充静态 HTML,并且此特定请求不需要是动态的或在构建后更新。

有什么方法可以让 getInitialProps 运行 只有 next export 构建时 没有 当客户端加载页面时?

这是好的做法吗?

对于版本 9.3 或更高版本it's recommended that you use getStaticProps 用于提供静态构建道具。

export async function getStaticProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

旧答案

有两种方法 是我发现的一种方法,可以防止 getInitialProps 中的代码在页面组件加载时 运行。

1。在该页面使用不带 next/link 的常规锚标记。

getInitialProps 仅在页面从 next/link 组件链接时运行。如果使用常规 JSX 锚点 <a href="/my-page">click me</a>,组件的 getInitialProps 而不是 被调用。将页面直接加载到 NextJS 静态站点页面不会调用 getInitialProps.

请注意,使用标准锚而不是 next/link 组件会导致整个页面刷新。

因为这是一个糟糕的解决方案,I've submitted a feature request


2。在 context 参数中使用 req 以有条件地在 getInitialProps.

中调用 API

我相信@evgenifotia 想要传达的是 req 在已导出的站点中未定义。

// example usage of API call in getInitialProps
import fetch from 'isomorphic-unfetch'

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async (ctx) => {
  const { req } = ctx // context object: { req, res, pathname, query, asPath }
  if (req) { // will only run during the build (next export)
    const res = await fetch('https://api.github.com/repos/zeit/next.js')
    const json = await res.json()
    return { stars: json.stargazers_count }
  }

  return {}
}

export default Page

有关 getInitialProps 的更多信息,请参阅 documentation。那里的一个例子确认 req 预计只会在服务器上定义(或在导出构建期间):

const userAgent = req ? req.headers['user-agent'] : navigator.userAgent`

第二个选项可能适用于某些情况,但在我的情况下,从 getInitialProps 返回空结果会影响组件的 this.props.


注:

浅路由不是答案。 According to the documentation(见“注释”部分):

Shallow routing works only for same page URL changes.

我找到了 NextJs 9.0.3 的解决方法(其他版本也可能有效,我没有测试)

// XXXPage is your page

XXXPage.getInitialProps = async (req) => {
  if (process.browser) {
    return __NEXT_DATA__.props.pageProps;
  }
  // original logic
}

已接受答案的更详细和更新版本:

  const isInBroswer = typeof window !== 'undefined';
  if (isInBroswer) {
    const appCustomPropsString =
      document.getElementById('__NEXT_DATA__')?.innerHTML;

    if (!appCustomPropsString) {
      throw new Error(`__NEXT_DATA__ script was not found`);
    }

    const appCustomProps = JSON.parse(appCustomPropsString).props;
    return appCustomProps;
  }