1. 在动态路由页面组件中获取数据
- 使用
getStaticProps
(适用于数据不经常变化的情况):
- 在动态路由页面组件(例如
pages/products/[productId].js
)中定义 getStaticProps
函数。此函数在构建时运行,它可以通过 context.params.productId
获取动态路由参数,然后利用该参数调用 API 获取商品详细信息。
- 示例代码:
export async function getStaticProps(context) {
const productId = context.params.productId;
const res = await fetch(`https://api.example.com/products/${productId}`);
const product = await res.json();
return {
props: {
product
},
revalidate: 60 * 60 * 24 // 一天后重新验证数据(可选,用于增量静态再生)
};
}
const ProductPage = ({ product }) => {
return (
<div>
<h1>{product.title}</h1>
<p>{product.description}</p>
</div>
);
};
export default ProductPage;
- 使用
getServerSideProps
(适用于数据实时性要求高的情况):
- 同样在动态路由页面组件中定义
getServerSideProps
函数。该函数在每次请求页面时运行,通过 context.params.productId
获取参数并调用 API。
- 示例代码:
export async function getServerSideProps(context) {
const productId = context.params.productId;
const res = await fetch(`https://api.example.com/products/${productId}`);
const product = await res.json();
return {
props: {
product
}
};
}
const ProductPage = ({ product }) => {
return (
<div>
<h1>{product.title}</h1>
<p>{product.description}</p>
</div>
);
};
export default ProductPage;
2. 在布局组件中获取数据
- 如果布局组件的数据相对固定:
- 可以在布局组件所在文件(例如
components/Layout.js
)的顶层使用 getStaticProps
,在构建时获取数据并传递给布局组件。这种数据通常是网站的通用信息,如网站标题、导航栏菜单等。
- 示例代码:
export async function getStaticProps() {
const res = await fetch('https://api.example.com/siteInfo');
const siteInfo = await res.json();
return {
props: {
siteInfo
}
};
}
const Layout = ({ children, siteInfo }) => {
return (
<div>
<header>
<h1>{siteInfo.siteTitle}</h1>
</header>
{children}
<footer>
<p>{siteInfo.copyright}</p>
</footer>
</div>
);
};
export default Layout;
- 如果布局组件的数据与动态路由相关:
- 可以将从动态路由页面组件获取的数据通过 props 层层传递到布局组件。例如,商品详情页布局可能需要商品的分类信息来设置特定样式,那么在动态路由页面组件获取商品详细信息后,将分类信息传递给布局组件。
3. 处理加载状态
- 在动态路由页面组件中:
- 如果使用
getStaticProps
或 getServerSideProps
,在组件渲染时数据已经获取,无需额外处理加载状态。但如果使用客户端数据获取(例如在 useEffect
中调用 API),可以使用一个状态变量来表示加载状态。
- 示例代码:
import { useState, useEffect } from'react';
const ProductPage = () => {
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const productId = '123'; // 假设的商品 ID
useEffect(() => {
const fetchProduct = async () => {
const res = await fetch(`https://api.example.com/products/${productId}`);
const data = await res.json();
setProduct(data);
setLoading(false);
};
fetchProduct();
}, []);
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>{product.title}</h1>
<p>{product.description}</p>
</div>
);
};
export default ProductPage;
- 在布局组件中:
- 类似地,如果布局组件的数据在客户端获取,也可以使用状态变量处理加载状态。例如,获取网站导航栏菜单数据时:
import { useState, useEffect } from'react';
const Layout = ({ children }) => {
const [menu, setMenu] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchMenu = async () => {
const res = await fetch('https://api.example.com/menu');
const data = await res.json();
setMenu(data);
setLoading(false);
};
fetchMenu();
}, []);
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<header>
{menu.map(item => (
<a href={item.link} key={item.id}>{item.name}</a>
))}
</header>
{children}
<footer>
<p>Copyright</p>
</footer>
</div>
);
};
export default Layout;
4. 错误处理
- 在数据获取函数中:
- 对于
fetch
操作,可以使用 try...catch
块捕获错误。在 getStaticProps
或 getServerSideProps
中:
export async function getStaticProps(context) {
try {
const productId = context.params.productId;
const res = await fetch(`https://api.example.com/products/${productId}`);
if (!res.ok) {
throw new Error('Network response was not ok');
}
const product = await res.json();
return {
props: {
product
},
revalidate: 60 * 60 * 24
};
} catch (error) {
return {
notFound: true // 返回 404 页面
};
}
}
- 在组件渲染中:
- 如果在组件内部(如
useEffect
中)获取数据,可以在捕获错误后设置一个错误状态,并在组件中显示相应的错误信息。
import { useState, useEffect } from'react';
const ProductPage = () => {
const [product, setProduct] = useState(null);
const [error, setError] = useState(null);
const productId = '123';
useEffect(() => {
const fetchProduct = async () => {
try {
const res = await fetch(`https://api.example.com/products/${productId}`);
if (!res.ok) {
throw new Error('Network response was not ok');
}
const data = await res.json();
setProduct(data);
} catch (error) {
setError(error.message);
}
};
fetchProduct();
}, []);
if (error) {
return <div>{error}</div>;
}
if (!product) {
return <div>Loading...</div>;
}
return (
<div>
<h1>{product.title}</h1>
<p>{product.description}</p>
</div>
);
};
export default ProductPage;