在 Next 14 的 appRouter 模式中接入 React-Redux

在 Next 14 的 appRouter 模式中接入 React-Redux

说明

Next.js 版本升级到 14 后,相比 13 版本是一个改动很大的大版本升级,很多概念或者使用方式 13 版本都有较大的区别,因此这里记录一些学习 14 版本的 Next.js 的心得体会或者问题。因为我这边构建项目选择的是 Next.js 新的路由模式 App Router,因此该文档是基于 App Router 路由模式的。

安装依赖

根据 react-redux 官方文档 的说明,使用如下面命令安装依赖:

pnpm add @reduxjs/toolkit react-redux

创建 store 模块

我们以创建一个 counterSlice 举例:
在项目根目录(或者 app 目录,或者其他目录),创建 store 目录,以及 react-redux 的主文件 store.ts,然后创建 /storemodules/counterSlice.ts,并写入如下代码:

//counterSlice.jsx"use client"; //this is a client side componentimport { createSlice } from "@reduxjs/toolkit";
import { RootState } from "../store";const initialState = {value: 0,
};export const counterSlice = createSlice({name: "counter",initialState,reducers: {increment: (state) => {state.value += 1;},decrement: (state) => {state.value -= 1;},incrementByAmount: (state, action) => {state.value += action.payload;},},
});export const { increment, decrement, incrementByAmount } = counterSlice.actions;export default counterSlice.reducer;export const selectCounter = (state: RootState) => state.counter.value;

**注意:**这里需要注意,在 next 中,redux 需要作为客户端渲染的模块,因此 store 模块的文件头部都需要加上使用客户端渲染的注解 "use client";
然后在 store.ts 里面写入如下代码:

//store.jsx"use client";
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import counterReducer from "./modules/counterSlice";
import { Provider } from "react-redux";const rootReducer = combineReducers({counter: counterReducer,//add all your reducers here
});export const store = configureStore({reducer: rootReducer,
});export function ReduxProvider({ children }) {return <Provider store={store}>{children}</Provider>;
}export type RootState = ReturnType<typeof store.getState>;export type AppDispatch = typeof store.dispatch;

ReduxProvider作为组件抛出去。

使用定义好的 store 模块

注册 Provider

我们可以在全局 layout 里面注册 Provider, 这样能保证我们的所有的客户端组件都能使用 Redux:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import ThemeRegistry from "@/app/components/themeRegistry/ThemeRegistry";
import HeaderBar from "@/app/components/layout/HeaderBar";
import { ReduxProvider } from "@/app/store/store";
import { useEffect } from "react";const inter = Inter({ subsets: ["latin"] });export const metadata: Metadata = {title: "Create Next App11",description: "Generated by create next app",
};function RootLayout({ children }: { children: React.ReactNode }) {return (<html lang="en"><body className={inter.className}><ReduxProvider><ThemeRegistry><HeaderBar />{children}</ThemeRegistry></ReduxProvider></body></html>);
}// export default wrapper.withRedux(RootLayout);
export default RootLayout;

组件中使用 redux

之前已经说了,reduxnext.js 中只能是作为客户端渲染模块使用,所以我们不能再任何的 page.tsx 路由页面组件中使用(除非这个路由页面有客户端渲染组件注解use client;,然而这种情况可能并不多见。),因此对于需要使用 redux 的地方,我们需要这块儿逻辑封装成客户端渲染的组件,比如:

"use client";
import {decrement,increment,selectCounter,
} from "@/app/store/modules/counterSlice";
import { AppDispatch } from "@/app/store/store";
import { Box, Button, Typography } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";export default function CounterControl() {const counter = useSelector(selectCounter);const dispatch = useDispatch<AppDispatch>();const handleChangeCounter = (type: "ADD" | "MINUS") => {dispatch(type === "ADD" ? increment() : decrement());};return (<Box><Typography variant="h1">{counter}</Typography><Box><Button variant="outlined" onClick={() => handleChangeCounter("ADD")}>ADD</Button><Buttonvariant="outlined"onClick={() => handleChangeCounter("MINUS")}sx={{ ml: 2 }}>MINUS</Button></Box></Box>);
}

这样子我们就可以在任意组件(包括路由组件 page.tsx)里面使用封装的这个 CounterControl 组件了:

import { Metadata } from "next";
import { Button } from "@mui/material";
import NavigateButton from "@/app/components/tools/NavigateButton";
import CounterControl from "../components/counter/CounterControl";export const metadata: Metadata = {title: "Users page",description: "Generated by create next app",
};export default function UsersPage() {return (<div><CounterControl /><Button sx={{ mx: 1 }} variant="contained">Hellow Mui</Button><NavigateButton destination="/" variant="contained" sx={{ mx: 2 }}>back</NavigateButton><h2>This is the User Index page</h2></div>);
}

以上就完成了在 Next.js 14App Router 路由模式中接入 react-redux 的全过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/174009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode491. Non-decreasing Subsequences

文章目录 一、题目二、题解 一、题目 Given an integer array nums, return all the different possible non-decreasing subsequences of the given array with at least two elements. You may return the answer in any order. Example 1: Input: nums [4,6,7,7] Output…

sqli-labs(5)

23. 判断是注释符被过滤了我们用‘1’‘1来闭合后面的’ 这里不能使用order by来判断列数直接通过union select来判断 -1 union select 1,2,3 and 11 -1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schemasecurity) ,3 an…

如何使用cpolar+Jellyfin自建私人影音平台【内网穿透】

&#x1f3a5; 个人主页&#xff1a;深鱼~ &#x1f525;收录专栏&#xff1a;cpolar &#x1f304;欢迎 &#x1f44d;点赞✍评论⭐收藏 文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpo…

Java[list/set]通用遍历方法之Iterator

//原始for遍历是用索引来进行遍历 但是现在我们的set集合里面是没有索引的 //所以原先的普通for遍历只能在list遍历中进行//以下的三种遍历方法可以在list和set两种类型中去使用 //—————————————————————————————————————————————…

SpringBoot参数校验@Validated和@Valid的使用

1、Validated和Valid区别 Validated&#xff1a;可以用在类、方法和方法参数上。但是不能用在成员属性&#xff08;字段&#xff09;上Valid&#xff1a;可以用在方法、构造函数、方法参数和成员属性&#xff08;字段&#xff09;上 2、引入依赖 Spring Boot 2.3 1 之前&…

Linux多线程基本概念

目录 ​编辑 1.什么是进程&#xff0c;线程&#xff0c;并发&#xff0c;并行 优点 缺点 什么资源是线程应该私有的呢 为什么线程切换成本更低呢 3.线程控制 pthread_create lpthread选项 makefile 代码实现 ps -aL 什么是LWP 轻量级进程ID与进程ID之间的区别 LWP与pthr…

软件测试行情堪忧,测试行业将迎来低谷?

前两天跟一个HR朋友聊天&#xff0c;她表示刚在boss上发布了一个普通测试岗位&#xff0c;不到一小时竟然收到了几百份简历。而且简历质量极高&#xff0c;这是往年不敢想象的。岗位少&#xff0c;竞争激烈&#xff0c;这是今年软件测试就业的真实写照&#xff0c;也是所有岗位…

SWT技巧

实现控件的刷新 问题可以简化如下&#xff0c;点击上方按钮&#xff0c;使下方按钮移动&#xff0c;但要求在监听事件里新建按钮对象&#xff0c;而不是使用原来的按钮&#xff08;原来的按钮被移除了&#xff09;。 解决代码如下&#xff1a; public class TestUI {protecte…

前端下载文件的方法-blob下载

前端经常会遇到下载文件的需求&#xff0c;后端一般提供的以下两种方法&#xff1a; 文件地址。后端直接提供要下载的文件地址&#xff0c;常用于图片、音视频等静态文件文件流。后端返回文件流&#xff0c;常用于excel等动态文件 一、a 标签下载 1、直接html使用a标签下载 …

【高效开发工具系列】PlantUML入门使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

SpringBoot : ch07 整合websocket

前言 当涉及到在Spring Boot应用程序中整合WebSocket时&#xff0c;我们可以使用Spring框架提供的功能来实现实时双向通信。WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议&#xff0c;它允许服务器主动向客户端发送消息&#xff0c;而不需要客户端发起请求。 …

学习Qt的网站

之前有一段时间准备学习Qt&#xff0c;当时找到的两个学习网站 Qt大课堂&#xff1a;Qt软件 (lgwimonday.cn) Qt学习之路&#xff1a;《Qt 学习之路 2》目录 - DevBean Tech World

aspose-words 跳过证书验证jar

优先用 aspose-words-19.3.jar &#xff0c;不需要读取license.xml&#xff0c;导出后直接水印&#xff0c;jar包最好直接放在项目resource目录下直接引用&#xff0c;要不下载不下来 public static String doc2pdf(String fileName, String filePath) {try {String oldFile f…

387. 字符串中的第一个唯一字符

387. 字符串中的第一个唯一字符 描述 : 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回 -1 。 题目 : 387. 字符串中的第一个唯一字符 分析 : 我们可以对字符串进行两次遍历&#xff0c;在第一次遍…

Redis原理之五种数据类型笔记

目录 String List Set ZSet ​ Hash String List Set ZSet Hash

Shell脚本:Linux Shell脚本学习指南(第二部分Shell编程)四

第二部分&#xff1a;Shell编程&#xff08;四&#xff09; 三十一、Shell test命令&#xff08;Shell []&#xff09;详解&#xff0c;附带所有选项及说明 test 是 Shell 内置命令&#xff0c;用来检测某个条件是否成立。test 通常和 if 语句一起使用&#xff0c;并且大部分…

RHEL开发者授权注册

$ sudo subscription-manager register --usernameusername --passwordpassword$ sudo subscription-manager attach --auto查看是否注册 Red Hat 订阅管理&#xff0c;请运行以下命令&#xff1a; $ sudo subscription-manager list --installed

【数据库】执行计划中的两趟算法机制原理,基于排序算法来分析,算法的限制,执行代价以及优化

基于排序的两趟算法 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定…

Java计算二叉树从根节点到叶子结点的最大路径和

要求从根节点到叶子结点的最大路径和&#xff0c;可以通过递归遍历二叉树来实现。对于二叉树中的每个节点&#xff0c;我们都可以考虑包含该节点的最大路径和。在递归的过程中&#xff0c;我们需要不断更新全局最大路径和。 具体的思路如下&#xff1a; 递归函数设计&#xff1…

服务化通信OPC实操

实操也是基于视频进行一些笔记&#xff0c;没得写就少写了 准备 Nuget包准备&#xff1a;OPCfoundation 一般都是使用Ua&#xff0c;当然也是有&#xff1a; 客户端链接服务器参数&#xff1a;IP Port 认证 登录用户名 Session 的实例化创建 进行使用&#xff1a; 因为Ses…