获取数据
使用fetch在服务器上获取数据
Next.js扩展了原生的fetch Web API,允许您在服务器上配置每个fetch
请求的缓存和重新验证行为。React通过在呈现React组件树时自动记忆fetch请求来扩展fetch。
您可以在服务器组件(Server Components)、路由处理程序(Route Handlers)和服务器操作(Server Actions)中使用async/await
与fetch
。
例如下面的例子:
//app/page.tsx
type User = {
id:string,
name:string,
email:string
}
async function getData() {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
if (!res.ok){
throw new Error('请求失败')
}
return res.json()
}
export default async function Home() {
const users:User[] = await getData()
return (
<main>
<Link href="/users">Users</Link>
<h1>用户列表</h1>
{users.map((user)=>(
<li key={user.id}>
<Link href={`users/${user.id}`}>{user.name}</Link>
</li>
))}
</main>
)
}
通过后端api获取到数据(通过服务端渲染)
-
前端页面
首先我们在app
目录下创建一个文章列表的文件posts
,设置一个动态路由[id]
,这样我们就可以通过路由获取到文章的id,看以下代码:
//app/posts/[id]/page.tsx
export default function PostID({params}:any) {
return <main className="min-h-screen p-24 " >
文章ID:{params.id}
</main>
}

-
后端api接口
接下来我们来写后端的api,首先在app
目录下面创建一个api/posts
目录,在posts
下面创建一个名为[id]
的动态路由,我们要根据前端传过来的id
,返回文章的内容。代码如下:
//app/api/posts/[id]/route.ts
import {NextResponse} from "next/server";
//有两篇文章
const posts:any = [
{
id:1,
title:"Next.js学习1",
description:"了解Next.js的基础知识1"
},
{
id:12,
title:"Next.js学习2",
description:"了解Next.js的基础知识2"
}
]
//文章筛选返回
export async function GET(request:Request,context:any) {
const { params } = context;
return NextResponse.json({
post:posts.find((item:any) =>item.id.toString() === params.id)
});
}
-
在前端发送请求
//app/posts/[id]/page.tsx
//通过id来查询文章
async function getPostById(postId:string) {
const response = await fetch(`http://localhost:3000/api/posts/${postId}`,{
method:"GET"
})
return response.json();
}
export default async function PostID( {params}:any) {
//调用根据id获取文章的方法
const { post } = await getPostById(params.id);
console.log('post',post)
return <main className="min-h-screen p-24 " >
<h1 className="text-lg text-slate-900 py-3">{post.title}</h1>
<p className="text-slate-500">{post.description}</p>
</main>
}
我们选择的是id为1的文章,在浏览器上是不会看到数据的(是服务端渲染),只有在terminal里面看到打印的post如下:

通过后端api获取到数据(通过客户端渲染)
如果你想在客户端获取到数据,首先我们要把页面改成客户端的,也就是设置'use client';
再来刷新一下页面,就会在浏览器的控制套看到:

我们会发现接口请求了很多次。 而且,在terminal里面也有打印,显然不是一个客户端请求,下面我们来改一下。
//app/posts/[id]/page.tsx
'use client';
import { useState ,useEffect } from "react";
//对Post这个类型进行了定义,该类型是一个对象,包含可选的title和description属性,这两个属性的类型都是字符串。
type Post = {
title?:string,
description?:string
}
export default function PostID({params}:any) {
//使用React的useState hook来创建一个名为post的状态变量和一个修改这个变量的函数setPost。
//这个状态变量的初始值被设定为null,类型为Post或者null。
const [post, setPost] = useState<Post | null>(null);
//定义了一个异步函数getPostById,用于发起http请求,从服务器读取id为params.id的post。
//如果读取成功,会使用setPost函数将读取到的post赋值给post状态变量。
const getPostById = async () =>{
try {
const response = await fetch(`http://localhost:3000/api/posts/${params.id}`,
{method:"GET"}
)
if (response) {
const {post} = await response.json()
console.log(response)
if (post) {
setPost(post)
}
}
}catch (e) {
console.log(e)
}
}
useEffect(() => {
getPostById();
}, []);
return <main className="min-h-screen p-24 " >
{post && <h1 className="text-lg text-slate-900 py-3">{post.title}</h1>}
{post &&<p className="text-slate-500">{post.description}</p>}
</main>
}
再来看我们的页面,此时浏览器上就能看到请求:

设置loading
当我们换成客户端渲染的时候,速度比服务端渲染慢了。这时我们可以加入一个加载的效果,你也可以因为一些UI的骨架组件。下面来简单的写一下:
'use client';
import { useState ,useEffect } from "react";
type Post = {
title?:string,
description?:string
}
export default function PostID({params}:any) {
const [post, setPost] = useState<Post | null>(null);
const [loading, setLoading] = useState(false);
const getPostById = async () =>{
setLoading(true)
console.log('222',loading)
try {
console.log('loading',loading)
const response = await fetch(`http://localhost:3000/api/posts/${params.id}`,
{method:"GET"}
)
if (response) {
const {post} = await response.json()
console.log(response)
if (post) {
setPost(post)
}
}
}catch (e) {
console.log(e)
}finally {
setLoading(false)
console.log('333',loading)
}
}
useEffect(() => {
getPostById();
}, []);
return <main className="min-h-screen p-24 " >
{loading && <div>loading</div>}
{!loading && <div>
{post && <h1 className="text-lg text-slate-900 py-3">{post.title}</h1>}
{post &&<p className="text-slate-500">{post.description}</p>}
</div>}
</main>
}
缓存
你在 App Router 中使用 fetch
功能时,它会自动配置为使用缓存。这扩展了 Web API 获取功能,因此可以使用选项来更改缓存设置。
默认情况下设置强制缓存。除了force-cache
之外,还有no-store
可以禁用缓存。
const response = await fetch('http://localhost:3000/api',
{cache:'no-store'}
)
设置后,无论访问接口多少次,缓存值都保持“MISS”。

由于我们正在向 http://localhost:3000/api 发送 GET 请求,因此我们将设置 console.log 来检查请求是否确实正在发送。
设置 next.revalidate
cache选项设置是否使用缓存,但通过设置next.revalidate
选项,可以指定缓存的生存期。一旦配置的生命周期结束,将执行新的获取函数。
秒数可以使用revalidate
值来设置,所以下面设置5秒。通过 fetch 进行访问,并且缓存值使用 5 秒,但之后会再次执行 fetch 函数。
const response = await fetch('http://localhost:3000/api/hello',
{
// cache:'no-store'
next: { revalidate: 5 },
}
)
原文始发于微信公众号(大前端编程教学):12.Next.js14 数据获取fetch、服务端请求和客户端请求以及缓存设置
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/224340.html