Reactjs NextJS:有没有办法只在服务器端调用某个东西,只在新页面加载时调用?

Reactjs NextJS:有没有办法只在服务器端调用某个东西,只在新页面加载时调用?,reactjs,react-hooks,next.js,Reactjs,React Hooks,Next.js,我们的团队最初使用getInitialProps创建了一个_app.tsx,并包含了一些类似于 if (!req) return {}; 作为第一行。其想法是使getInitialProps仅在服务器端运行,仅在初始页面加载时运行。我们认为这是一个安全的假设,因为stackoverflow回答中经常重复的建议是getInitialProps运行客户端页面转换 我们后来发现,如果您正在转换到具有getServerSideProps的页面,则getInitialProps实际上会运行服务器端页面转

我们的团队最初使用getInitialProps创建了一个_app.tsx,并包含了一些类似于

if (!req) return {};
作为第一行。其想法是使getInitialProps仅在服务器端运行,仅在初始页面加载时运行。我们认为这是一个安全的假设,因为stackoverflow回答中经常重复的建议是getInitialProps运行客户端页面转换

我们后来发现,如果您正在转换到具有getServerSideProps的页面,则getInitialProps实际上会运行服务器端页面转换

因此,这不符合我们的目的-我们有几个在getInitialProps中进行的网络查询,这些查询是在我们的大多数页面转换中进行的,因为我们的大多数页面都有getServerSideProps,而我们的目的是只在新页面应用程序加载上运行这些查询

我们可以只在组件装载上使用useEffect,但我们希望在服务器端而不是客户端运行这些查询,以防止视觉闪烁

我正在学习如何设置一个包含setState的上下文,但初始测试表明它的初始setState在客户端和服务器端都运行:

...

const getString = (): string => {
  console.log('about to set string!');
  return 'string';
};

const PagePropsProvider: React.FC<IProps> = ({ pageProps, children }) => {
  const [sample, setSample] = useState<string>(getString());

  return <PagePropsContext.Provider value={pageProps}>{children}</PagePropsContext.Provider>;
};
...

对于auth上下文之类的东西,我希望_app.tsx的getInitialProps在页面加载时请求初始用户对象服务器端,从props将其提供给上下文,而不是让应用在每次页面转换时不必要地重新请求初始用户对象。如果我能阻止getInitialProps在页面转换上运行,我就可以做到这一点。有没有办法阻止getInitialProps在这些页面转换上运行?还是用一种更惯用的方式来实现我们的目标?理想情况下,我们希望完全避免使用getInitialProps,但getServerSideProps仍然存在相同的问题,即如何使其仅在新页面加载时调用。

getInitialProps仅在第一次加载时被称为服务器端。在页面转换过程中,getInitialProps只在浏览器端调用,而getServerSideProps在第一次加载和所有转换过程中将在服务器端调用

如果只希望在第一次加载期间从服务器端获取数据,则应仅使用getInitialProps,如下所示:

MyPage.getInitialProps = async () => {
  if (typeof window !== 'undefined') {
    return {} // browser-side, fetch data directly in component
  }

  console.log('server-side !');
  const data = {} // fetch your data
  return { data }
};
然后,您可以使用收到的道具设置上下文状态

const PagePropsProvider: React.FC<IProps> = ({ pageProps, children }) => {
  const [state, setState] = useState()
  useEffect(() => {
    if (pageProps.data) {
      setState(pageProps.data)
    }
  }, [pageProps.data])
  return <PagePropsContext.Provider value={state}>{children}</PagePropsContext.Provider>;
};
getInitialProps仅在第一次加载时被称为服务器端。在页面转换过程中,getInitialProps只在浏览器端调用,而getServerSideProps在第一次加载和所有转换过程中将在服务器端调用

如果只希望在第一次加载期间从服务器端获取数据,则应仅使用getInitialProps,如下所示:

MyPage.getInitialProps = async () => {
  if (typeof window !== 'undefined') {
    return {} // browser-side, fetch data directly in component
  }

  console.log('server-side !');
  const data = {} // fetch your data
  return { data }
};
然后,您可以使用收到的道具设置上下文状态

const PagePropsProvider: React.FC<IProps> = ({ pageProps, children }) => {
  const [state, setState] = useState()
  useEffect(() => {
    if (pageProps.data) {
      setState(pageProps.data)
    }
  }, [pageProps.data])
  return <PagePropsContext.Provider value={state}>{children}</PagePropsContext.Provider>;
};
通过仔细检查getInitialProps和getServerSideProps中的上下文对象,我注意到一个元素似乎可以可靠地指示客户端页面转换和新页面加载之间的区别:context.req.url似乎总是以/u next/data开头用于客户端页面转换,即使代码本身getInitialProps或getServerSideProps正在服务器端运行

因此,我们正在尝试以下代码:

if (!req || (req.url && req.url.startsWith('/_next/data'))) {
  // return early
}
...
我不确定这是可靠的还是在未来的版本中受支持,因此我也在这里打开了一个功能请求:

通过仔细检查getInitialProps和getServerSideProps中的上下文对象,我注意到一个元素似乎可以可靠地指示客户端页面转换和新页面加载之间的区别:context.req.url似乎总是以/u next/data开头用于客户端页面转换,即使代码本身getInitialProps或getServerSideProps正在服务器端运行

因此,我们正在尝试以下代码:

if (!req || (req.url && req.url.startsWith('/_next/data'))) {
  // return early
}
...
我不确定这是可靠的还是在未来的版本中受支持,因此我也在这里打开了一个功能请求:


你能用饼干做这个吗?。。。我想,但应用程序可以卸载并重新加载,而不必关闭浏览器。我很好奇是否有一种更具反应性/下一步的方法。你能用饼干来做这个吗?。。。我想,但应用程序可以卸载并重新加载,而不必关闭浏览器。我很好奇是否有更多的react/next-ish方法来实现它。不幸的是,这不是我们的选项,因为我们的一些页面确实需要getServerSideProps。当导航到包含getServerSideProps的页面时,来自_app.js的getInitialProps被称为服务器端。好的,我理解这个问题。出于好奇,你可以用getServerSideProps实现什么,而用getInitialProps无法实现什么?你是对的。。。如果我们将所有页面更改为使用getInitialProps而不是getServerSideProps,那么问题就会消失。主要的阻力在于NextJS显然正在远离getInitialProps,所以感觉像是在倒退。另一个好处是节省了捆绑包的大小,因为getServerSideProps的内容不需要压缩
et交付给客户。这些都不是交易破坏者,所以如果我们找不到更好的解决方案,这可能是我们的方向。不过,我已经向nextJS团队提出了另一种解决方案,我将在另一个回答中提及。不幸的是,这不是我们的选项,因为我们的一些页面确实需要GetServerSideProp。当导航到包含getServerSideProps的页面时,来自_app.js的getInitialProps被称为服务器端。好的,我理解这个问题。出于好奇,你可以用getServerSideProps实现什么,而用getInitialProps无法实现什么?你是对的。。。如果我们将所有页面更改为使用getInitialProps而不是getServerSideProps,那么问题就会消失。主要的阻力在于NextJS显然正在远离getInitialProps,所以感觉像是在倒退。另一个好处是节省捆绑包的大小,因为getServerSideProps的内容不会传递到客户端。这些都不是交易破坏者,所以如果我们找不到更好的解决方案,这可能是我们的方向。不过,我已经向nextJS团队提出了另一种解决方案,我将在另一个答案中提及。这是正确的答案。您还可以尝试通过一些req.header来区分客户机和服务器,例如“sec fetch mode”:“navigate”,但url似乎更可靠,尽管它仍然非常粗糙。这是正确的答案。您还可以尝试通过一些req.header来区分客户机和服务器,比如“sec fetch mode”:“navigate”,但url看起来更可靠,尽管它仍然非常粗糙。