Next.js - 服务器端渲染 (SSR)
服务器端渲染 (SSR) 是 Next.js 中使用的一种性能优化技术,其中每个请求都会在服务器上生成 HTML。在本章中,我们将学习什么是服务器端渲染、如何实现它以及客户端渲染和服务器端渲染之间的区别。
什么是服务器端渲染?
服务器端渲染 (SSR) 是 Next.js 中的一项功能,其中服务器处理请求并将完全渲染的 HTML 页面发送到客户端。在服务器端渲染中,每个请求都会生成 HTML 页面。因此,浏览器不必等待 JavaScript 执行后再显示内容。这使页面加载速度更快,并且对搜索引擎可见。
换句话说,服务器端渲染可确保网页的动态内容在发送到客户端之前在服务器上获取和渲染。
服务器端渲染如何工作?
当用户请求页面时,服务器:
- 获取页面所需的数据。
- 根据数据动态生成 HTML 内容。
- 将完全呈现的 HTML 页面发送到用户的浏览器。
此过程可确保用户尽快获得完全加载的页面,这对 SEO 和性能至关重要的应用程序有益。
实现服务器端渲染
可以使用 `getServerSideProps()` 函数实现服务器端渲染。请参阅以下代码:
export async function getServerSideProps() { // 从 API 获取数据 const response = await fetch('https://link/to/api'); const data = await response.json(); // 将数据作为 prop 传递给页面组件 return { props: { data } }; } export default function Page({ data }) { return ( <div> <h1>Server-Side Rendered Data</h1> <ul> {data.map((item) => ( <li key={item.id}>{item.title}</li> ))} </ul> </div> ); }
无服务器端渲染的示例
下面的示例显示了客户端渲染方法。此处数据在用户的浏览器上获取和渲染。这可能会导致显示数据的延迟,直到 JavaScript 完全执行。在代码中,您可以看到我们添加了一个加载组件,直到从服务器获取 API 数据。
'use client'; // 定义为客户端组件 import { useState, useEffect } from 'react'; export default function CSRPage() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { try { const response = await fetch('https://link/to/api'); const json = await response.json(); setData(json); } catch (error) { console.error('Error fetching data:', error); } finally { setLoading(false); } }; fetchData(); }, []); return ( <div> <h1>{loading ? 'Loading...' : 'Client-Side Rendered Page'}</h1> {!loading && data && ( <ul> {data.map((item) => ( <li key={item.id}>{item.title}</li> ))} </ul> )} </div> ); }
输出
在输出中,您可以看到显示加载组件,直到 API 数据准备好显示。
服务器端渲染示例
在下面的代码中,我们使用服务器端渲染改进了上述组件。在这里,即使我们添加了加载栏,但由于 API 数据获取和显示速度很快,因此它在输出中不可见。
export default async function SSRPage() { let loading = false; const response = await fetch('https://link/to/api'); const data = await response.json(); loading = true; // Stop the loading spinner return ( <div> <h1> {loading ? 'Loading...' : 'Server-Side Rendered Page'} </h1> <ul> {data.slice(0, 5).map((todo: { id: number; title: string }) => ( <li key={todo.id}>{todo.title}</li> ))} </ul> </div> ); }
输出
由于服务器端渲染,输出可立即显示,无需任何加载。