面试题答案
一键面试通过 Next.js 动态路由获取产品 ID
在 Next.js 中,动态路由以方括号包裹参数的形式定义。对于 /product/[productId]
这样的路由,我们可以在页面组件中通过 useRouter
钩子或 getStaticProps
、getServerSideProps
的上下文对象来获取 productId
。
- 使用
useRouter
钩子(客户端获取)import { useRouter } from 'next/router'; const ProductPage = () => { const router = useRouter(); const { productId } = router.query; return ( <div> <p>Product ID: {productId}</p> </div> ); }; export default ProductPage;
- 在
getStaticProps
或getServerSideProps
中获取(服务端获取)export async function getStaticProps(context) { const { productId } = context.params; // 这里可以根据 productId 获取产品数据 return { props: { productId }, revalidate: 60 // 如果使用增量静态再生,设置重新验证时间 }; } export async function getServerSideProps(context) { const { productId } = context.params; // 这里可以根据 productId 进行服务器端数据获取 return { props: { productId } }; } const ProductPage = ({ productId }) => { return ( <div> <p>Product ID: {productId}</p> </div> ); }; export default ProductPage;
结合 SSR 或 SSG 技术高效渲染产品详情页及相关推荐部分
- 静态站点生成(SSG)
- 数据获取:在
getStaticProps
函数中,根据获取到的productId
从数据库或 API 中获取产品详情数据以及相关推荐产品数据。例如:
import { getAllProducts, getProductById } from '../lib/api'; export async function getStaticProps(context) { const { productId } = context.params; const product = await getProductById(productId); const relatedProducts = await getAllProducts({ category: product.category }); return { props: { product, relatedProducts }, revalidate: 60 // 可选,设置增量静态再生时间 }; } export async function getStaticPaths() { const products = await getAllProducts(); const paths = products.map(product => ({ params: { productId: product.id.toString() } })); return { paths, fallback: false }; } const ProductPage = ({ product, relatedProducts }) => { return ( <div> <h1>{product.title}</h1> {/* 展示产品详情 */} <h2>Related Products</h2> {relatedProducts.map(related => ( <div key={related.id}>{related.title}</div> ))} </div> ); }; export default ProductPage;
- 优势:SSG 在构建时生成 HTML 页面,适合内容变化不频繁的产品详情页。可以极大提高页面加载速度,因为用户直接获取预生成的 HTML。
- 适用场景:适用于大多数电商产品详情页,尤其是产品信息和推荐相对稳定,不需要实时更新的情况。
- 数据获取:在
- 服务器端渲染(SSR)
- 数据获取:在
getServerSideProps
函数中,同样根据productId
获取产品详情和相关推荐数据。
import { getAllProducts, getProductById } from '../lib/api'; export async function getServerSideProps(context) { const { productId } = context.params; const product = await getProductById(productId); const relatedProducts = await getAllProducts({ category: product.category }); return { props: { product, relatedProducts } }; } const ProductPage = ({ product, relatedProducts }) => { return ( <div> <h1>{product.title}</h1> {/* 展示产品详情 */} <h2>Related Products</h2> {relatedProducts.map(related => ( <div key={related.id}>{related.title}</div> ))} </div> ); }; export default ProductPage;
- 优势:SSR 在每次请求时生成 HTML,能够实时获取最新的数据,适合产品信息或推荐可能频繁变化的场景。
- 适用场景:适用于产品数据更新频繁,或者推荐算法依赖实时用户行为数据的情况。
- 数据获取:在
处理缓存以提升性能
- 客户端缓存
- 浏览器缓存:设置合适的 HTTP 缓存头,如
Cache - Control
和ETag
。对于静态资源(如图片、CSS、JS),可以设置较长的缓存时间,因为它们通常不会频繁变化。对于产品详情页的 HTML,可以根据产品更新频率设置合理的缓存时间。例如,对于变化不频繁的产品,可以设置Cache - Control: public, max - age = 3600
(缓存 1 小时)。 - 前端状态管理缓存:使用 Redux 或 MobX 等状态管理库时,可以在客户端缓存产品数据。当用户在应用内导航到其他产品详情页又返回时,直接从客户端状态中获取数据,避免重复请求。
- 浏览器缓存:设置合适的 HTTP 缓存头,如
- 服务器端缓存
- 数据库缓存:如果使用 SQL 数据库,可以利用数据库自带的查询缓存机制。例如,MySQL 有查询缓存功能,可以缓存查询结果,当下次相同查询到来时直接返回缓存结果。对于 NoSQL 数据库如 Redis,可以手动将常用的产品数据和推荐数据缓存到 Redis 中。当请求到达时,先检查 Redis 中是否有缓存数据,如果有则直接返回,避免数据库查询。
- 应用层缓存:在 Node.js 应用中,可以使用
lru - cache
等库实现简单的内存缓存。在获取产品数据和推荐数据的函数中,检查缓存中是否已经存在相应数据,如果存在则直接返回缓存数据,否则从数据库或 API 获取并更新缓存。例如:
const LRU = require('lru - cache'); const cache = new LRU({ max: 100, // 最大缓存项数 maxAge: 1000 * 60 * 10 // 缓存项的最大存活时间,10 分钟 }); async function getProductById(productId) { let product = cache.get(productId); if (!product) { product = await // 从数据库或 API 获取产品数据 cache.set(productId, product); } return product; }