当前位置: 首页 > news >正文

NextJs 数据篇 - 数据获取 | 缓存 | Server Actions

NextJs 数据篇 - 数据获取 | 缓存 | Server Actions

  • 前言
  • 一. 数据获取 fetch
    • 1.1 缓存 caching
      • ① 服务端组件使用fetch
      • ② 路由处理器 GET 请求使用fetch
    • 1.2 重新验证 revalidating
      • ① 基于时间的重新验证
      • ② 按需重新验证
        • revalidatePath
        • revalidateTag
    • 1.3 缓存的退出方式
  • 二. Server Actions
    • 2.1 PageRouter下 API 简单案例
    • 2.2 AppRouter 下 Server Actions 简单案例

前言

之前讲了:

  • NextJs 初级篇 - 安装 | 路由 | 中间件
  • NextJs 渲染篇 - 什么是CSR、SSR、SSG、ISR 和服务端/客户端组件

这篇文章就打算专门讲一下NextJs中的数据获取方式、缓存以及什么是Server Actions

一. 数据获取 fetch

NextJs 中,在服务端使用 fetch 函数是常规的数据请求方式,它扩展了原生的API,在此基础上有这么几个功能(针对服务端的请求):

  • caching:缓存
  • revalidating :重新验证

例如这么一个简单的服务端组件:

export default async function Page() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return (<ul>{data.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}

1.1 缓存 caching

默认情况下,NextJs 会自动缓存服务端中 fetch 请求的返回值。但是在以下情况下不会自动缓存:

  • Server Action 中使用的时候。
  • 在定义了非 GET 方法的路由处理程序中使用。

即在服务端组件内部或者只有 GET 方法的路由处理程序中使用 fetch 函数,返回结果会自动缓存。

接下来我们来测试一下缓存,为了更加直观的让大家看到缓存的生效,我们可以在next.config.mjs 文件中增加以下配置,这样在fetch的时候,就会打印相关的信息,包括缓存是否命中

/** @type {import('next').NextConfig} */
const nextConfig = {logging: {fetches: {fullUrl: true}}
};export default nextConfig;

① 服务端组件使用fetch

例如我有这么一个服务端组件:

export default async function Page() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return (<ul>{data.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}

页面多次访问后:可以发现缓存命中
在这里插入图片描述

② 路由处理器 GET 请求使用fetch

// app/api/getData/route.ts
import { NextResponse } from 'next/server'export async function GET() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return NextResponse.json(data)
}

然后多次访问 http://localhost:3000/api/getData,结果如下:

在这里插入图片描述

1.2 重新验证 revalidating

重新验证的定义:清除缓存数据,然后重新获取最新的数据。 而NextJs 中提供了两种方式完成重新验证:

  • 基于时间的重新验证:根据指定的时间,自动进行重新验证。
  • 按需重新验证:根据事件手动重新验证数据。

① 基于时间的重新验证

这种验证方式,只需要在fetch的时候,增加参数revalidate即可,如下代表这个请求的缓存时长为10秒钟

fetch('https://...', { next: { revalidate: 10 } })

或者在路由段配置项中进行配置,可以再页面上或者路由处理程序中增加以下属性的导出:

// layout.jsx | page.jsx | route.js
export const revalidate = 10

② 按需重新验证

我们可以在路由处理程序中或者 Server Actions 中通过两种方式来实现按需重新验证:

  • 路径 revalidatePath
  • 缓存标签 revalidateTag
revalidatePath

我们写一个简单的页面,这个页面每次加载的时候都会随机加载一个图片,但是由于fetch被缓存了,加载多次还是同一个图片。

async function getData() {// 接口每次调用都会返回一个随机的猫猫图片数据const res = await fetch('https://api.thecatapi.com/v1/images/search')if (!res.ok) {throw new Error('Failed to fetch data')}return res.json()
}export default async function Page() {const data = await getData()return <img src={data[0].url} width="300" />
}

效果如下:
在这里插入图片描述

那我如何按需让这个fetch请求做到刷新呢?例如我创建这么一个路由处理程序:

// app/api/revalidatePathTest/route.ts
import { revalidatePath } from 'next/cache'
import { NextRequest } from 'next/server'export async function GET(request: NextRequest) {const path = request.nextUrl.searchParams.get('path')if (path) {revalidatePath(path)return Response.json({ revalidated: true, now: Date.now() })}return Response.json({revalidated: false,now: Date.now(),message: 'Missing path to revalidate',})
}

这段代码啥意思呢?

  • 如果我请求的地址没有参数 refreshPath,那就是个普通的接口。
  • 如果我请求的地址带上参数 refreshPath,就会通过revalidatePath 函数,重新验证对应路由或者接口。

倘若我访问:http://localhost:3000/api/revalidatePathTest?refreshPath=/,之后再访问:http://localhost:3000/,可见图片发生了刷新:
在这里插入图片描述
说明成功让路由 / 进行了重新验证(缓存刷新)

revalidateTag

除此之外,NextJs中有一个路由标签系统,即revalidateTag,它的实现逻辑如下:

使用 fetch 的时候,设置一个或者多个标签标记请求
调用 revalidateTag 方法重新验证该标签对应的所有请求

例如我们修改app/page.tsx文件:

async function getData() {// 接口每次调用都会返回一个随机的猫猫图片数据const res = await fetch('https://api.thecatapi.com/v1/images/search', { next: { tags: ['refresh'] } })if (!res.ok) {throw new Error('Failed to fetch data')}return res.json()
}export default async function Page() {const data = await getData()return <img src={data[0].url} width="300" />
}

修改revalidatePathTest

// app/api/revalidatePathTest/route.ts
import { revalidatePath } from 'next/cache'
import { NextRequest } from 'next/server'export async function GET(request: NextRequest) {const tag = request.nextUrl.searchParams.get('tag')revalidateTag(tag)return Response.json({ revalidated: true, now: Date.now() })
}

操作如下:
在这里插入图片描述
我们可以发现:

  1. 当我们多次刷新 http://localhost:3000/ ,图片并没有改变,因为缓存的作用。
  2. 当我们访问:http://localhost:3000/api/revalidatePathTest?tag=refresh,我们带上了指定的tag。值为refresh
  3. 此时再次访问首页,发现图片修改。
  4. 而我们的图片在fetch的时候,await fetch('https://api.thecatapi.com/v1/images/search', { next: { tags: ['refresh'] } }),指定了tagrefresh
  5. 因此可以联动做到重新验证。

1.3 缓存的退出方式

上面说的都是重新验证,说白了就是缓存的一种刷新机制,那么我们是否有办法主动退出缓存呢?

当使用 fetch 的时候,若满足以下情形,可以做到默认退出缓存机制:

  • fetch 请求添加了 cache: 'no-store' 或者 revalidate: 0 属性。例如
fetch('', { cache: 'no-store' })
  • fetch 请求在路由处理程序中并使用了其他方法,例如POST
  • 函数体内使用到了 headerscookies 等方法。
export async function GET(request) {const token = request.cookies.get('token')return Response.json({ data: new Date().toLocaleTimeString() })
}
  • 配置了路由段选项 const dynamic = 'force-dynamic'
export const dynamic = 'force-dynamic'
  • 配置了路由段选项 fetchCache ,默认会跳过缓存

二. Server Actions

Server Actions 是指在服务端执行的异步函数但是可以在服务端和客户端组件中使用。 我们什么情况下可以用到这个呢?

  • PageRouter 情况下,若需要前后端进行交互,则需要先定义一个接口。
  • AppRouter 情况下,这种操作则可以简化为 Server Actions 。我们可以定义一个 Server Actions ,然后直接在客户端使用获取数据。

它的基本定义方式就是通过 'use server' 声明,一般分为两种:

  • 模块级别:在文件的顶部声明,那么该文件下声明的所有导出函数都是Server Actions
  • 函数级别:在函数内部的顶端添加声明,那么只有该函数是Server Actions

例如:

// 函数级别 
async function getData() {'use server'// ...
}// 模块级别 app/serverActions/action.ts
'use server'
export async function getData() {// ...
}
export async function create() {// ...
}

2.1 PageRouter下 API 简单案例

我们定义一个接口:
在这里插入图片描述

import { NextRequest, NextResponse } from 'next/server'export async function GET(request: NextRequest) {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return NextResponse.json(data)
}

然后定义一个页面,通过API的方式从后端取数据。

'use client'import { useEffect, useState } from "react"export default function Page() {const [data, setData] = useState<any>(null)async function getList() {const data = await (await fetch('/api/getData')).json();setData(data);}useEffect(() => {getList();}, [])return (<ul>{data?.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}

2.2 AppRouter 下 Server Actions 简单案例

我们来看下使用Server Actions的简单案例,一般我们定义一个actions文件夹:
在这里插入图片描述
里面的函数如下:

'use server'
export async function getData() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return data;
}

然后在组件中使用:服务端组件和客户端组件都可以使用

import { getData } from '../actions/actions'export default async function Page() {const data = await getData();return (<ul>{data.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}

可以看到Server Actions代码更加简洁,无需手动创建一个接口。并且这个函数可以在代码的任何一个地方使用。

相关文章:

NextJs 数据篇 - 数据获取 | 缓存 | Server Actions

NextJs 数据篇 - 数据获取 | 缓存 | Server Actions 前言一. 数据获取 fetch1.1 缓存 caching① 服务端组件使用fetch② 路由处理器 GET 请求使用fetch 1.2 重新验证 revalidating① 基于时间的重新验证② 按需重新验证revalidatePathrevalidateTag 1.3 缓存的退出方式 二. Ser…...

腾讯开源人像照片生成视频模型V-Express

网址 https://github.com/tencent-ailab/V-Express 下面是github里的翻译&#xff1a; 在人像视频生成领域&#xff0c;使用单张图像生成人像视频变得越来越普遍。一种常见的方法是利用生成模型来增强受控发电的适配器。 但是&#xff0c;控制信号的强度可能会有所不同&…...

pytorch使用DataParallel并行化保存和加载模型(单卡、多卡各种情况讲解)

话不多说&#xff0c;直接进入正题。 &#xff01;&#xff01;&#xff01;不过要注意一点&#xff0c;本文保存模型采用的都是只保存模型参数的情况&#xff0c;而不是保存整个模型的情况。一定要看清楚再用啊&#xff01; 1 单卡训练&#xff0c;单卡加载 #保存模型 torc…...

PS初级|写在纸上的字怎么抠成透明背景?

前言 上一次咱们讲了很多很多很多的抠图教程&#xff0c;这次继续。。。最近有小伙伴问我&#xff1a;如果是写在纸上的字&#xff0c;要怎么把它抠成透明背景。 这个其实很简单&#xff0c;直接来说就是选择通道来抠。但有一点要注意的是&#xff0c;写在纸上的字&#xff0…...

Docker面试整理-Docker的网络是如何工作的?

Docker 的网络功能允许容器以多种方式连接到彼此、宿主机以及外部网络。Docker 使用不同的网络驱动来支持这些连接,每种驱动方式都适用于特定的用途。理解 Docker 的网络是如何工作的,可以帮助你更好地设计和管理容器化应用的通信。 Docker 网络驱动 bridge:默认网络驱动。当…...

获得抖音商品评论 API 返回值

公共参数 名称类型必须描述keyString是调用key&#xff08;获取key和密钥​​​​​​​&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString否[yes,no]默认yes&am…...

Qt | QtBluetooth(蓝牙电脑当服务端+手机当客户端) 配对成功啦

01、前言 没有演示,因为穷,电脑没有带蓝牙,但是已在其他电脑进行演示,可以满足配对,后期再补充和手机进行聊天,如果有聊天的记得私聊我,好处大大滴。02、QtBlueTooth 简介 QtBluetooth 是一个跨平台的蓝牙库,它允许开发者创建在支持蓝牙的设备上运行的应用程序。这个库…...

我找到了全网最低价买服务器的 bug !!!

拍断大腿 周五&#xff0c;放松一下&#xff0c;给大家分享下我最近的事儿&#xff0c;以及带大家薅个&#xff08;可能会有&#xff09;的羊毛。 上个月&#xff0c;家里买了 Apple TV&#xff08;可理解为苹果的电视盒子&#xff09;装了 infuse&#xff08;一个在电视盒子上…...

聚类的外部指标(Purity, ARI, NMI, ACC) 和内部指标(NCC,Entropy,Compactness,Silhouette Index)

在聚类分析中,外部指标和内部指标用于评估聚类结果的质量。外部指标需要知道真实的类别标签,而内部指标则仅基于聚类结果本身进行评估。 外部指标 Purity (纯度): 计算聚类结果中每个簇中最多数目的样本所属的类别,并计算所有簇的该类别样本数之和占所有样本数的比例。 Pyt…...

国标GB/T 28181详解:国标GBT28181-2022的客户端主动发起历史视音频回放流程

目录 一、定义 二、作用 1、提供有效的数据回顾机制 2、增强监控系统的功能性 3、保障数据传输与存储的可靠性 4、实现精细化的操作与控制 5、促进监控系统的集成与发展 三、历史视音频回放的基本要求 四、命令流程 1、流程图 2、流程描述 五、协议接口 1、会话控…...

Vue项目安装axios报错npm error code ERESOLVE npm error ERESOLVE could not resolve解决方法

在Vue项目中安装axios时报错 解决方法&#xff1a;在npm命令后面加--legacy-peer-deps 例如&#xff1a;npm install axios --save --legacy-peer-deps 因为别的需求我把node版本重装到了最新版&#xff08;不知道是不是这个原因&#xff09;&#xff0c;后来在项目中安装axi…...

【Linux】Centos7升级内核的方法:yum更新(ELRepo)

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…...

【CSS】object-fit 和 object-position 属性详解

目录 object-fit属性属性值&#xff1a;使用场景&#xff1a; object-position 属性语法&#xff1a;例如&#xff1a;使用场景&#xff1a; object-fit和object-position是CSS属性&#xff0c;用于控制图像或视频在其容器中的适应和定位方式。 object-fit属性 属性值&#xf…...

【算法专题--栈】最小栈--高频面试题(图文详解,小白一看就会!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐解题方法--1 ⭐解题方法--2 四、总结 五、共勉 一、前言 最小栈这道题&#xff0c;可以说是--栈专题--&#xff0c;比较经典的一道题&#xff0c;也是在面试中频率较高的一道题目&#xff0c;通常在面试中&#xff0c;面试官可…...

Vite项目构建chrome extension,实现多入口

本项目使用Vite5 Vue3进行构建。 要使用vite工程构建浏览器插件&#xff0c;无非就是要实现popup页面和options页面。这就需要在项目中用到多入口打包&#xff08;生成多个html文件&#xff09;。 实现思路&#xff1a; 通过配置vite工程&#xff0c;使得项目打包后有两个h…...

【vector模拟实现】附加代码讲解

vector模拟实现 一、看源代码简单实现1. push_backcapacity&#xff08;容量&#xff09;sizereserve&#xff08;扩容&#xff09;operator[ ] &#xff08;元素访问&#xff09; 2. pop_back3. itorator&#xff08;迭代器&#xff09;4.insert & erase &#xff08;头插…...

本地运行ChatTTS

TTS 是将文字转为语音的模型&#xff0c;最近很火的开源 TTS 项目&#xff0c;本地可以运行&#xff0c;运行环境 M2 Max&#xff0c;差不多每秒钟 4&#xff5e;&#xff5e;5 个字。本文将介绍如何在本地运行 ChatTTS。 下载源码 首先下载源代码 git clone https://github…...

应用解析 | 面向智能网联汽车的产教融合解决方案

背景介绍 随着科技的飞速发展&#xff0c;智能网联汽车已成为汽车产业的新宠&#xff0c;引领着未来出行的潮流。然而&#xff0c;行业的高速发展也带来了对高素质技术技能人才的迫切需求。为满足这一需求&#xff0c;推动教育链、人才链与产业链、创新链的深度融合&#xff0…...

华为设备动态路由OSPF(单区域+多区域)实验

动态路由OSPF的配置 OSPF分类两种情况&#xff1a;单区域 多区域路由 OSPF单区域路由配置 OSPF&#xff1a;开放最短路径优先的路由协议。属于大型动态路由协议&#xff0c;适用于中大型的园区网。 网络拓扑&#xff1a; 配置步骤&#xff1a; 1.完成基本配置&#xff08;略&a…...

R语言探索与分析19-CPI的分析和研究

一、选题背景 CPI&#xff08;居民消费价格指数&#xff09;作为一个重要的宏观经济指标&#xff0c;扮演着评估通货膨胀和居民生活水平的关键角色。在湖北省这个经济活跃的地区&#xff0c;CPI的波动对于居民生活、企业经营以及政府宏观经济政策制定都具有重要的影响。因此&a…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...