最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I use getInitialProps only during the NextJS site build? - Stack Overflow

programmeradmin7浏览0评论

When using NextJS to build a static site, I would like the getInitialProps method to fire only during the build step and not on the client.

In the build step, NextJS runs the getInitialProps method before each ponent's rendered HTML is used to generate the page's static HTML. On the client, NextJS also runs this method before the page ponent is rendered in order to return the necessary props for the ponent. Thus, large requests can delay the client's first paint as this is a blocking request.

// 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('.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

I'm unwilling to move my slow API request to ponentDidMount in order to avoid the blocking request because I want to use the data returned during the build step to populate the static HTML, and this particular request doesn't need to be dynamic or updated after the build.

Is there a way I can make getInitialProps run only when next export builds and not as the client loads the page?

Is this good practice?

When using NextJS to build a static site, I would like the getInitialProps method to fire only during the build step and not on the client.

In the build step, NextJS runs the getInitialProps method before each ponent's rendered HTML is used to generate the page's static HTML. On the client, NextJS also runs this method before the page ponent is rendered in order to return the necessary props for the ponent. Thus, large requests can delay the client's first paint as this is a blocking request.

// 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./repos/zeit/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

I'm unwilling to move my slow API request to ponentDidMount in order to avoid the blocking request because I want to use the data returned during the build step to populate the static HTML, and this particular request doesn't need to be dynamic or updated after the build.

Is there a way I can make getInitialProps run only when next export builds and not as the client loads the page?

Is this good practice?

Share Improve this question asked Sep 11, 2019 at 23:00 brettinternetbrettinternet 5758 silver badges22 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 13

I found the workaround with NextJs 9.0.3 (other versions may also work, I didn't test that)

// XXXPage is your page

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

For version 9.3 or newer, it's remended that you use getStaticProps for providing static build props.

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

Old answer

There are two ways is one way that I've found to prevent code in getInitialProps from running on a page ponent load.

1. Use a regular anchor tag without next/link to that page.

getInitialProps only runs when the page is linked from a next/link ponent. If a regular JSX anchor <a href="/my-page">click me</a> is used instead, the ponent's getInitialProps will not be invoked. Direct page loads to NextJS static site pages will not invoke getInitialProps.

Note that using a standard anchor instead of the next/link ponent will cause a full page refresh.

Because this is a poor solution, I've submitted a feature request.


2. Use req in the context argument to conditionally make the API call in getInitialProps.

I believe what @evgenifotia wanted to convey is that req is undefined in a site that's been exported.

// 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./repos/zeit/next.js')
    const json = await res.json()
    return { stars: json.stargazers_count }
  }

  return {}
}

export default Page

For more information about getInitialProps, see the documentation. One example there confirms that req is expected to only be defined on the server (or during the exporting build):

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

This second option may work for some scenarios, but not mine where returning an empty result from getInitialProps will affect the ponent's this.props.


Note:

Shallow routing is not the answer. According to the documentation (see under "Notes" section):

Shallow routing works only for same page URL changes.

A more detailed and updated version as of the accepted answer:

  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;
  }
发布评论

评论列表(0)

  1. 暂无评论