React:Redux

Redux引入

Redux感觉像组件通信的中介

state存放被管理的状态

action是申请改哪些数据,传入什么参数

reducer是怎么修改数据

我的理解更像是action像一个储存方法的对象,reducer是具体的方法的实现,不同的方法实现也不一样

store是个仓库,存储应用状态的仓库

自己实现redux对状态的管理

首先进行初始化:

import { createSlice } from '@reduxjs/toolkit';createSlice({name: 'counter', // slice 的名称initialState: {count: 0, // 初始状态},
});

初始化是对slice的初始化,也就是切片,切片的名字叫counter,初始状态为{counter:0}

有了状态以后设置修改状态的方法

import { createSlice } from '@reduxjs/toolkit'
const counterStore=createSlice({//初始化name: 'counter',initialState: {count:0 },//编写修改数据的方法,同步方法,支持直接修改reducers: {increment(state) {state.count++},decrement(state) {state.count--}}
}) 

解构获取这两个方法:

//解构actionCreater函数
const { increment, decrement } = counterStore.actions

获取reducer:

//获取reducer
const reducer = counterStore.reducer

按需导出reducer和action creators,导出actioncreators是为了派发action,触发状态的更新

reducer在Redux store里处理action,更新状态

//按需导出actionCreater
export { increment, decrement }
//默认导出的方式导出reducer
export default reducer

然后在index.js文件里组合

configureStore是 Redux Toolkit 提供的一个函数,用于创建 Redux store

import { configureStore } from "@reduxjs/toolkit";

counter Reducer是从 ./modules/counterStore 文件中导入的 reducer

import { configureStore } from "@reduxjs/toolkit";
//导入子模块reducer
import counterReducer from './modules/counterStore'

这里的reducer是个对象,将多个子模块的reducer组合在一起

counter是模块的名称,counterReducer是模块的reducer

由configureStore创建Redux store,支持异步操作(不过这里写的都是同步)

import { configureStore } from "@reduxjs/toolkit";
//导入子模块reducer
import counterReducer from './modules/counterStore'
configureStore({reducer: {counter:counterReducer
}
})

然后导出store,在组件里使用

在组件里使用需要用中间件链接,这步叫为react注入store:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import reportWebVitals from './reportWebVitals';
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { Provider } from 'react-redux';
import store from './store'const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><Provider store={store}>{/* //注入 */}<App/></Provider></React.StrictMode>
)

要使用store里的数据,需要用到一个钩子函数useSelector

在App组件里调用useSelector

import { useSelector } from "react-redux";
function App() {const {count}=useSelector(state=>state.counter)return (<div className='App'>
{count}</div>)
}
export default App

然后在index.js引入App并调用就好了

一些注意事项

默认导出的文件应该用默认导入的文件引入:

//默认导出/导入
export default store
import store from './store'

这叫命名导出/导入:

//命名导出
const name = 'John';
function greet() {console.log('Hello!');
}export { name, greet }; // 导出多个内容
//命名导入
import { name, greet } from './module';

如果你认为你的代码和配置完全正确,但是还是报错(我就这样),那可能是webpack把错误缓存下来了,需要清理webpack:

//删除package-lock.json
rm -rf node_modules package-lock.json
//重新下载
npm install
//然后启动
npm start

react组件里修改store的数据

引入App.js

useDispatch是封装好的钩子,dispatch方法调用的时候把一个dispatch赋值给这个形参

import { useDispatch, useSelector } from "react-redux";
//导入actionCreater
import {increment,decrement} from './store/modules/counterStore'
function App() {const { count } = useSelector(state => state.counter)const dispatch=useDispatch()return (<div className='App'><button onClick={()=>dispatch(decrement())}>-</button>{count}<button onClick={()=>dispatch(increment())}>+</button></div>)
}
export default App  

这样就可以控制数字的+-了

actions提交参数

修改reduer,将state.count更新为action.payload的值

  reducers: {increment(state) {state.count++},decrement(state) {state.count--},addToNum(state,action) {state.count=action.payload}}

在App.js里添加一个按钮,并传入参数:

 <button onClick={() => dispatch(addToNum(0))}>

异步状态
 

很遗憾我没有实现出来,因为远程axios一直失败,可能是远程的后端数据的服务器倒闭了

如果想实现可以在本地写一个json,但是我做了四个小时的实验实在撑不下去了

所以就这样吧

放一下代码: 

//channelStore
import { createSlice } from '@reduxjs/toolkit'
//导入axiosimport axios from 'axios';
const channelStore= createSlice({name: 'channel',initialState: {channelList:[]},reducers: {setChannels(state, action) {state.channelList=action.payload}}
})
//异步请求部分
const {setChannels}=channelStore.actions
const fetchChannelList = () => {return async(dispatch) => {const res = await axios.get('https://geek.itheima.net/v1_0/channels').then(response => console.log(response.data)).catch(error => console.error("请求失败", error));dispatch(setChannels(res.data.data.channels))}
}
export { fetchChannelList }
const channelReducer = channelStore.reducer
export default channelReducer 
//\src\store\index.js
import { configureStore } from "@reduxjs/toolkit";
//导入子模块reducer
import counterReducer from './modules/counterStore';
import channelReducer  from './modules/counterStore';
const store= configureStore({reducer: {counter:counterReducer,channel:channelReducer
}})
export default store
//\src\App.jsx
import { useDispatch, useSelector } from "react-redux";
import { increment, decrement, addToNum } from './store/modules/counterStore'
import { fetchChannelList } from "./store/modules/channelStore";
import { useEffect } from 'react'
import { createSelector } from 'reselect'// 使用 createSelector 创建 memoized 选择器
const selectCount = createSelector(state => state.counter,counter => counter.count
);const selectChannelList = createSelector(state => state.channels, channels => channels?.channelList || [] // 确保不为空
);function App() {const count = useSelector(selectCount);const channelList = useSelector(selectChannelList);const dispatch = useDispatch();useEffect(() => {dispatch(fetchChannelList()); // 需要执行 fetchChannelList()}, [dispatch]);
//useEffect在App首次渲染的时候执行一次
//dispatch是ReduxStore里提供的方法,可以触发action,触发状态的更新return (<div className='App'><button onClick={() => dispatch(decrement())}>-</button><button onClick={() => dispatch(addToNum(0))}>点我置为0</button>{count}<button onClick={() => dispatch(increment())}>+</button><ul>{channelList.map(item => <li key={item.id}>{item.name}</li>)}//主要修改了这部分,把数据渲染出来</ul></div>);
}export default App;

在上面代码里最让人疑惑的是为什么dispatch会作为useEffect的依赖项,它是严格会改变的方法吗?

方法是函数,函数也可以做useEffect的依赖项,而react官方文档推荐useEffect里用到的所有外部变量都应该被作为依赖,确保useEffect能在变量变化时重新执行,如果 Redux 未来更新,导致dispatch变了,就可能导致useEffect访问的是过时的dispatch,可能引发 Bug

像这样,会报警告👆

Redux调试-devtools

点击Chart可以看到这样一个图,我是因为没获取到后端数据,所以节点很少

正常来说会给你一个这样的状态管理图

Raw可以看展示的数据

点击这个的左右按键可以回到上一次或下次状态改变的情况,方便做一些大项目的数据调试

还有一些redux的其他重要方法,后面会学到,例如store.subscribe(listener)、store.getState()

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

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

相关文章

CoDrivingLLM

CoDrivingLLM 思路 1.输入和输出 输入 算法的输入包括车辆当前时刻的状态 S t S_t St​ &#xff0c;这个状态包含了车辆的位置、速度、行驶方向等信息&#xff1b;以及参与协同驾驶的联网自动驾驶汽车列表C&#xff0c;用于确定需要进行决策的车辆集合。 输出 输出为车辆…

微信小程序接入deepseek

先上效果 话不多说&#xff0c;直接上代码&#xff08;本人用的hbuilder Xuniapp&#xff09; <template><view class"container"><!-- 聊天内容区域 --><scroll-view class"chat-list" scroll-y :scroll-top"scrollTop":…

xxxxx

从别人blog偷的~,自己复习用 爱奇艺 一面 介绍项目项目中用到的设计模式项目中如何处理高并发Redis集群Redis RDB 和 AOF原理Redis除了缓存和分布式锁还能干什么&#xff1f;数据库如何优化&#xff0c;索引的数据结构&#xff0c;多表联合如何优化RedissonAOP逻辑&#xff…

Yocto + 树莓派摄像头驱动完整指南

—— 从驱动配置、Yocto 构建&#xff0c;到 OpenCV 实战 在树莓派上运行摄像头&#xff0c;在官方的 Raspberry Pi OS 可能很简单&#xff0c;但在 Yocto 项目中&#xff0c;需要手动配置驱动、设备树、软件依赖 才能确保摄像头正常工作。本篇文章从 BSP 驱动配置、Yocto 关键…

总结(尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开发教程)

1.Vue简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece 1.1.性能的提升 打包大小减少41%。 初次渲染快55%, 更新渲染快133%。 内存减少54%。 1.2.源码的升级 使用Proxy代替defineProperty实现响应式。 重写虚拟DOM的实现和Tree-Shak…

【五.LangChain技术与应用】【8.LangChain提示词模板基础:从入门到精通】

早上八点,你端着咖啡打开IDE,老板刚甩来需求:“做个能自动生成产品描述的AI工具”。你自信满满地打开ChatGPT的API文档,结果半小时后对着满屏的"输出结果不稳定"、"格式总出错"抓耳挠腮——这时候你真需要好好认识下LangChain里的提示词模板了。 一、…

基于编程语言的建筑行业施工图设计系统开发可行性研究————从参数化建模到全流程自动化的技术路径分析

基于编程语言的建筑行业施工图设计系统开发可行性研究————从参数化建模到全流程自动化的技术路径分析 文章目录 **基于编程语言的建筑行业施工图设计系统开发可行性研究————从参数化建模到全流程自动化的技术路径分析** 摘要引言一、技术可行性深度剖析1.1 现有编程语言…

【Linux文件操作篇】IO基础——被打开的文件,引入文件描述符

--------------------------------------------------------------------------------------------------------------------------------- 每日鸡汤&#xff1a;现实会告诉你&#xff0c;不努力就会被生活给踩死。无需找什么借口&#xff0c;一无所有&#xff0c;就是拼的理由…

Docker 学习(三)——数据管理、端口映射、容器互联

一、数据管理 容器中的管理数据主要有两种方式&#xff1a; 数据卷 &#xff08;Data Volumes&#xff09;&#xff1a; 容器内数据直接映射到本地主机环境&#xff1b; 数据 卷容器&#xff08; Data Volume Containers&#xff09;&#xff1a; 使用特定容器维护数据卷 1.…

3月5日作业

代码作业&#xff1a; #!/bin/bash# 清空目录函数 safe_clear_dir() {local dir"$1"local name"$2"if [ -d "$dir" ]; thenwhile true; doread -p "检测到 $name 目录已存在&#xff0c;请选择操作&#xff1a; 1) 清空目录内容 2) 保留目…

通义万相2.1:开启视频生成新时代

文章摘要&#xff1a;通义万相 2.1 是一款在人工智能视频生成领域具有里程碑意义的工具&#xff0c;它通过核心技术的升级和创新&#xff0c;为创作者提供了更强大、更智能的创作能力。本文详细介绍了通义万相 2.1 的背景、核心技术、功能特性、性能评测、用户反馈以及应用场景…

GPU/CUDA 发展编年史:从 3D 渲染到 AI 大模型时代(上)

目录 文章目录 目录1960s~1999&#xff1a;GPU 的诞生&#xff1a;光栅化&#xff08;Rasterization&#xff09;3D 渲染算法的硬件化实现之路学术界算法研究历程工业界产品研发历程光栅化技术原理光栅化技术的软件实现&#xff1a;OpenGL 3D 渲染管线设计1. 顶点处理&#xff…

如何直接导出某个conda环境中的包, 然后直接用 pip install -r requirements.txt 在新环境中安装

1. 导出 Conda 环境配置 conda list --export > conda_requirements.txt这将生成一个 conda_requirements.txt 文件&#xff0c;其中包含当前环境中所有包的列表及其版本信息。 2. 转换为 requirements.txt 文件 grep -v "^#" conda_requirements.txt | cut -d …

【我的 PWN 学习手札】House of Emma

House of Emma 参考文献 第七届“湖湘杯” House _OF _Emma | 设计思路与解析-安全KER - 安全资讯平台 文章 - house of emma 心得体会 - 先知社区 前一篇博客【我的 PWN 学习手札】House of Kiwi-CSDN博客的利用手法有两个关键点&#xff0c;其一是利用__malloc_assert进入…

沃尔玛跨境电商自养号技术指南,助力销量腾飞

在跨境电商领域&#xff0c;沃尔玛平台为卖家提供了广阔的市场空间。对于技术型卖家而言&#xff0c;利用自养号技术提升产品销量是一项极具潜力的策略。本文将深入探讨沃尔玛自养号技术&#xff0c;从原理到实践&#xff0c;为你提供全面的技术指南。 自养号技术原理与架构 自…

Redis|集群 Cluster

文章目录 是什么能干嘛集群算法-分片-槽位slotredis集群的槽位slotredis集群的分片分片槽位的优势slot槽位映射——业界的3种解决方案小厂&#xff1a;哈希取余分区中厂&#xff1a;一致性哈希算法分区大厂&#xff1a;哈希槽分区 面试题&#xff1a;为什么 Redis 集群的最大槽…

DeepSeek R1助力,腾讯AI代码助手解锁音乐创作新

目录 1. DeepSeekR1模型简介2. 歌词创作流程2.1 准备工作2.2 歌词生成技巧 3. 音乐制作环节3.1 主流AI音乐生成平台 4. 歌曲欣赏5. 总结展望 1. DeepSeekR1模型简介 腾讯AI代码助手最新推出的DeepSeekR1模型不仅在代码生成方面表现出色&#xff0c;其强大的自然语言处理能力也…

学习threejs,使用LineBasicMaterial基础线材质

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.LineBasicMaterial1.…

Spring Boot 整合 JMS-ActiveMQ,并安装 ActiveMQ

1. 安装 ActiveMQ 1.1 下载 ActiveMQ 访问 ActiveMQ 官方下载页面&#xff0c;根据你的操作系统选择合适的版本进行下载。这里以 Linux 系统&#xff0c;Java环境1.8版本为例&#xff0c;下载 apache-activemq-5.16.7-bin.tar.gz。 1.2 解压文件 将下载的压缩包解压到指定目…

C语言学习笔记-初阶(28)操作符详解2

1. 逗号操作符、逗号表达式 exp1, exp2, exp3, …expN 逗号表达式&#xff0c;就是用逗号隔开的多个表达式。 逗号表达式&#xff0c;从左向右依次执行。整个表达式的结果是最后一个表达式的结果。 //代码1 int a 1; int b 2; int c (a>b, ab10, a, ba1);//逗号表达…