页面数据和 UI 呈现
在上节的内容中,我们大致了解了 Next.js 在两种模式下的数据获取方式。在这种中,我们深入这部分,既然有了数据就需要在页面中呈现。
初始的全局数据在页面中的呈现
这里的初始的全局数据是指:所有页面都需要用到的数据。比如站点的 SEO 信息,其他配置项。
这些数据必须在第一时间加载,并且为了 SSR 能够正确渲染 SEO 信息,这些数据的获取必须在服务端进行。
传统路由(Page Router)模式
在 Next.js 传统路由模式中,这个步骤一般在 _app.jsx
文件中进行,使用 getInitialProps
获取数据。
在这里 _app.jsx
入口,充当了页面根布局,在传统的路由模式下,获取初始的全局数据也只有下面的一种方式。
Important而在前面章节提到的
getServerSideProps
在这里并不适用,这也是为什么虽然一直推getServerSideProps
也没有删除getInitialProps
方法。
上面的例子中,使用 getInitialProps
获取了初始的全局数据,并且用 <Head />
和 <title />
给站点加上了标题。当然你也可以加入其他的 SEO 信息,如果你的 SEO 信息都是动态的,那么这样会十分好用。
如上的根布局的数据需要传递到页面,页面中也会使用到全局的数据。
使用上下文传递
例如,在 posts
页面我需要改变其网页标题,需要使用页面的数据和原标题的拼接;然后使用全局数据的 siteOwner
字段。我们需要在 _app.jsx
使用 Context 向下传递数据。
那么,这样的改造之后页面成功获取到全局数据,SSR 渲染的 HTML 是 SEO 完备的。我们观察 /posts/1
页面的 view-source:
避免重复的数据获取
在上面的 _app.jsx
中,我们虚拟了 fetchRootData
函数去获取数据,注意这个方法中的 console.log
,可以用它鉴定数据的获取频次。
当我现在在同一个路由下,更换 params 以切换页面,你会发现全局数据一直在刷新。
这是因为在传统路由中并没有 Layout 的概念,所有的页面 + _app.jsx
为一个整体,所以在每次跳转新页面都需要重新执行一遍 _app
的逻辑。
我们需要缓存这个数据以便每次路由跳转都会重新刷新数据。然而官方并没有解决这个问题,直到新版路由系统的出现。但是不幸的是两者是无法共存的,那么在传统的路由模式下解决这个问题,我们需要利用一点手段。
首先,转换页面的数据获取方式为 getInitialProps
而不是 getServerSideProps
。
然后,利用 getInitialProps
是混合请求,即前面章节提到的,在转换为 CSR 之后,路由的跳转时请求的数据都由浏览器实现,而不是服务器的特征。那么,我们对 _app.jsx
的 getInitialProps
也进行改造。
这里利用了如果在浏览器调用,那么使用缓存的数据;而服务器只会在页面的 SSR 所以不受影响。
上面的代码示例,可以在 codesandbox 中亲自尝试。
App Router 模式
在 App Router 模式下,不再有 _app.jsx
的页面路由。而是所有的页面都是由一个或者多个 Layout 构成的,Layout 之间相互嵌套最后组成完整的页面。
所以获取全局数据的写法就变得非常的简单了。我们只需要定义一个根布局。
同理在 posts
页面也可以定义异步服务端组件。
这里有两种方式在页面中获取全局数据。
一是和传统路由模式下一样,使用 Context 传递,不过这样的话,由于服务端组件无法使用 Hooks,所以如果这样做你就需要把服务端组件转换为客户端组件。这个方法会丢失服务端组件带来的好处,所以没有特殊情况我们不选择这个方法。
我们可以按需把用到全局数据的单独抽离一个成客户端组件,以消费 Context。
页面定义维持服务端组件。
由于 RootLayout 在路由切换之后并不会被卸载,所以 Layout 上的数据会被缓存,因为,你也不必担心页面跳转会重新请求全局数据。
第二种,使用 cache
函数缓存本次渲染的数据。这样可以所有的渲染仅在服务端完成。
然后在 posts
中这样调用。
由于被缓存,所以并不会因为这个方法在 RootLayout 和 PostPage 中调用二次而请求数据两次。
但是,在路由切换时,会重复调用获取全局数据的方法。
这时候我们还需要配合 Next.js
魔改的 fetch
进行使用才能解决 Dedup。
我们模拟一个真实接口。
调用方法为:
现在我们页面之间跳转,观察真实 API 的调用。
发现数据都被 Next.js 缓存了,真实接口并没有调用。但是此方法,只有服务端执行的 fetch
才有效,这也是 all in rsc 的数据获取方式。
上面的代码示例在:
那么,到这里这节的内容差不多就结束了。下一节,将描述如何让死的数据在接入 WebSocket 之后活起来。
最后更新于 2024/7/26 16:15:59
本书还在编写中..
前往 https://innei.in/posts/tech/my-first-nextjs-book-here#comment 发表你的观点吧。