Redux 与 React 状态管理精讲:从基础到实战

引言

Redux 是一个广泛使用的 JavaScript 状态管理库,尤其适用于 React 应用。它提供了一种可预测的方式来管理应用的状态,使得状态的变更变得可控和可追踪。本教程将从 Redux 的基本概念讲起,逐步深入到与 React 结合使用的最佳实践,以及如何处理异步操作和调试。

Redux 简介

Redux 允许你将应用的状态集中存储在一个全局的 store 中,并通过纯函数 reducer 来描述状态的变化。这种集中式的状态管理方式简化了组件间的通信,并且易于调试。

为什么使用 Redux?

  • 独立性:Redux 可以独立于框架运行,不仅限于 React。
  • 简化通信:无视组件层级,简化组件间的数据传递。
  • 数据流清晰:单向数据流使得状态变更易于追踪和定位问题。
  • 调试友好:配套的调试工具如 Redux DevTools 提供了强大的调试支持。

Redux 快速体验

实现一个计数器

不依赖任何框架或构建工具,使用纯 JavaScript 和 Redux API 来实现一个简单的计数器。

  1. 定义 reducer 函数,根据 action 返回新的状态。
  2. 使用 createStore 创建 store 实例。
  3. 使用 subscribe 订阅状态变化。
  4. 使用 dispatch 提交 action,触发状态变更。
  5. 使用 getState 获取最新状态并更新视图。
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button><script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script> <script>// 1. 定义reducer函数 // 作用: 根据不同的action对象,返回不同的新的state// state: 管理的数据初始状态// action: 对象 type 标记当前想要做什么样的修改function reducer (state = { count: 0 }, action) {// 数据不可变:基于原始状态生成一个新的状态if (action.type === 'INCREMENT') {return { count: state.count + 1 }}if (action.type === 'DECREMENT') {return { count: state.count - 1 }}return state}// 2. 使用reducer函数生成store实例const store = Redux.createStore(reducer)// 3. 通过store实例的subscribe订阅数据变化// 回调函数可以在每次state发生变化的时候自动执行store.subscribe(() => {console.log('state变化了', store.getState())document.getElementById('count').innerText = store.getState().count})// 4. 通过store实例的dispatch函数提交action更改状态 const inBtn = document.getElementById('increment')inBtn.addEventListener('click', () => {// 增store.dispatch({type: 'INCREMENT'})})const dBtn = document.getElementById('decrement')dBtn.addEventListener('click', () => {// 减store.dispatch({type: 'DECREMENT'})})// 5. 通过store实例的getState方法获取最新状态更新到视图中</script>

Redux 数据流架构

Redux 的数据流向清晰,从 stateaction,再到 reducer,最后回到新的 state

Redux 与 React 环境准备

虽然 Redux 可以独立于 React 使用,但通常我们会将其与 React 结合,利用 react-redux 库来连接 Redux 和 React 组件。

配套工具

  • Redux Toolkit (RTK):官方推荐的编写 Redux 逻辑的方式,简化代码。
  • react-redux:连接 Redux 和 React 的桥梁。

配置基础环境

使用 Create React App (CRA) 创建项目,并安装必要的依赖。

npx create-react-app react-redux 
npm i @reduxjs/toolkit  react-redux 
npm run start 

Redux 与 React 实现计数器

使用 Redux Toolkit 创建 Store

利用 createSlice API 简化 slice 的创建,包括初始状态、reducers 和 actions。

//store/modules/conterStore.js
import { createSlice } from '@reduxjs/toolkit'const counterStore = createSlice({// 模块名称独一无二name: 'counter',// 初始化数据stateinitialState: {count: 1},// 修改数据的同步方法reducers: {increment (state) {state.count++},decrement(state){state.count--}}
})// 解构出actionCreater函数
const { increment, decrement } = counterStore.actions// 获取reducer函数
const counterReducer = counterStore.reducer// 以按需导出的方式导出actionCreater函数和reducer函数
export { increment, decrement }
// 以默认导出的方式导出reducer函数
export default counterReducer

为 React 注入 Store

使用 Provider 组件将 store 传递给 React 应用,建立连接。

// 项目的src/index.js中
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 导入store
import store from './store'
// 导入store提供组件Provider
import { Provider } from 'react-redux'ReactDOM.createRoot(document.getElementById('root')).render(// 提供store数据<Provider store={store}><App /></Provider>
)

React 组件使用 Store 数据

使用 useSelector 钩子从 store 中读取数据,使用 useDispatch 钩子分发 actions。

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

React 组件修改 Store 中的数据

使用 useDispatch 钩子生成提交 action 对象的 dispatch 函数。

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

Redux 与 React 提交 Action 传参

在 action 创建函数中添加参数,允许在 dispatch 时传递额外的数据。

//conterStore.js
import { createSlice } from '@reduxjs/toolkit'const counterStore = createSlice({// 模块名称独一无二name: 'counter',// 初始化数据stateinitialState: {count: 0},// 修改数据的同步方法reducers: {increment (state) {state.count++},decrement(state){state.count--},addToNum(state, action){state.count += action.payload}}
})// 解构出actionCreater函数
const { increment, decrement, addToNum } = counterStore.actions// 获取reducer函数
const reducer = counterStore.reducer// 以按需导出的方式导出actionCreater函数和reducer函数
export { increment, decrement, addToNum }
// 以默认导出的方式导出reducer函数
export default reducer
//App.js
import './App.css';
import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement, addToNum } from './store/modules/counterStore';function App() {const count = useSelector(state => state.counter.count);const dispatch = useDispatch();return (<div className="App"><button onClick={() => dispatch(increment())}>Increment</button>{count}<button onClick={() => dispatch(decrement())}>Decrement</button><button onClick={() => dispatch(addToNum(10))}>Add 10</button><button onClick={() => dispatch(addToNum(20))}>Add 20</button></div>);
}export default App;

Redux 异步 Action 处理

封装异步逻辑,如 API 请求,并在获取数据后 dispatch 同步 action 更新状态。

//store/modules/channelStore.js
import { createSlice } from '@reduxjs/toolkit'
import axios from 'axios'const channelStore = createSlice({name: 'channel',initialState: {channelList: []},reducers: {setChannelList (state, action) {state.channelList = action.payload}}
})// 创建异步
const { setChannelList } = channelStore.actions
const url = 'http://geek.itheima.net/v1_0/channels'
// 封装一个函数 在函数中return一个新函数 在新函数中封装异步
// 得到数据之后通过dispatch函数 触发修改
const fetchChannelList = () => {return async (dispatch) => {const res = await axios.get(url)dispatch(setChannelList(res.data.data.channels))}
}export { fetchChannelList }const channelReducer = channelStore.reducer
export default channelReducer//store/index.js
import { configureStore } from '@reduxjs/toolkit'import counterReducer from './modules/counterStore'
import channelReducer from './modules/channelStore'const store = configureStore({reducer: {counter: counterReducer,channel: channelReducer}
})export default store
//App.js
import './App.css';
import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement, addToNum } from './store/modules/counterStore';
import { fetchChannelList } from './store/modules/channelStore';
import { useEffect } from 'react';function App() {const count = useSelector(state => state.counter.count);const {channelList} = useSelector(state => state.channel);const dispatch = useDispatch();//使用useEffect触发异步请求执行useEffect(() => {dispatch(fetchChannelList());}, [dispatch]);return (<div className="App"><button onClick={() => dispatch(increment())}>Increment</button>{count}<button onClick={() => dispatch(decrement())}>Decrement</button><button onClick={() => dispatch(addToNum(10))}>Add 10</button><button onClick={() => dispatch(addToNum(20))}>Add 20</button><ul>{channelList.map(task => <li key={task.id}>{task.name}</li>)}</ul></div>);
}export default App;

Redux 调试 - DevTools

使用 Redux DevTools 进行状态管理和 action 的调试,提供实时的 state 展示和 action 追踪。

结语

Redux 提供了一种强大且可预测的方式来管理应用的状态。通过本教程,你已经了解了 Redux 的基本概念、如何在 React 中使用 Redux,以及如何处理异步操作和调试。希望这能帮助你更好地构建和管理复杂的前端应用状态。

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

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

相关文章

滑动窗口练习6-找到字符串中所有字母异位词

题目链接&#xff1a;**. - 力扣&#xff08;LeetCode&#xff09;** 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串&#…

java Collections.singletonList方法介绍

Collections.singletonList 是 Java 集合框架中的一个静态方法,用于创建一个包含单个元素的不可变列表。这种列表的大小固定为1,并且不允许添加或删除元素。 具体解释 Collections 类: Collections 是一个包含静态方法的类,这些方法用于操作或返回集合。它包括各种实用工具…

《程序猿入职必会(6) · 返回结果统一封装》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

Profinet从站转TCP/IP协议转化网关(功能与配置)

如何将Profinet和TCP/IP网络连接通讯起来呢?近来几天有几个朋友问到这个问题&#xff0c;那么作者在这里统一说明一下。其实有一个不错的设备产品可以很轻易地解决这个问题&#xff0c;名为JM-DNT-PN。接下来作者就从该设备的功能及配置详细说明一下。 一&#xff0c;设备主要…

AIGC(Artificial Intelligence Generated Content)

随着人工智能技术的飞速发展&#xff0c;AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;在各个领域的应用日益广泛&#xff0c;其中也包括前端开发的重要部分——CSS&#xff08;层叠样式表&#xff09;的优化。CSS作为网页设计中控制布局和样式的关键…

el-table合计行更新问题

说明&#xff1a;在使用el-table自带的底部合计功能时&#xff0c;初始界面不会显示合计内容 解决方案&#xff1a;使用 doLayout()方法 updated() {this.$nextTick(() > {this.$refs[inventorySumTable].doLayout();});},完整代码&#xff1a; // show-summary&#xff1a…

电子文件怎么盖章?

电子文件怎么盖章&#xff1f;电子文件盖章是数字化办公中常见的操作&#xff0c;包括盖电子公章和电子骑缝章。以下是针对这两种情况的详细步骤&#xff1a; 一、盖电子公章 方法一&#xff1a;使用专业软件 选择软件&#xff1a;选择一款专业的电子签名或PDF编辑软件&…

Bugku的web题目get,post

1.web基础$_GET http://114.67.175.224:17587/ OK明显的代码审计题目。 让我们看看代码&#xff0c;先get获取what参数变量&#xff0c;如果what变量‘flag’&#xff0c;输出flag。 该题为GET传参&#xff0c;可直接在url后面加参数 在url后加上?whatflag 即可获得flag 2…

速盾:移动端cdn和pc端cdn加速一样吗?

CDN&#xff08;Content Delivery Network&#xff09;是分布在不同地理位置的服务器集群&#xff0c;用于存储、传输和交付网络内容&#xff0c;旨在提高用户访问网站的速度和性能。移动端CDN和PC端CDN在原理上是相同的&#xff0c;都是通过将网站的静态内容缓存在离用户更近的…

科普文:科普文:springcloud之-Hystrix服务容错

Hystrix概念 Hystrix 服务容错保护 的概念和说明 这就是大名鼎鼎的&#xff1a;豪猪 豪猪的英文就是&#xff1a;Hystrix&#xff0c;国外一些大牛的程序员在给自己的架构起名字的时候&#xff0c;往往就这么特别。哪天咱们中国人自己也能写出些架构&#xff0c;咱们就按照中…

2024后端开发面试题总结

一、前言 上一篇离职贴发布之后仿佛登上了热门&#xff0c;就连曾经阿里的师兄都看到了我的分享&#xff0c;这波流量真是受宠若惊&#xff01; 回到正题&#xff0c;文章火之后&#xff0c;一些同学急切想要让我分享一下面试内容&#xff0c;回忆了几个晚上顺便总结一下&#…

【VS2019安装+QT配置】

【VS2019安装QT配置】 1. 前言2. 下载visual studio20193. visual studio2019安装4. 环境配置4.1 系统环境变量配置4.2 qt插件开发 5. Visual Studio导入QT项目6. 总结 1. 前言 前期安装了qt&#xff0c;发现creator编辑器并不好用&#xff0c;一点都不时髦。在李大师的指导下&…

MongoDB - 比较查询操作符$eq | 数组查询操作符 $eleMatch

文章目录 1. $eq 比较查询操作符1.1 基本类型字段1.2 嵌入式文档字段1.3 数组字段 2. $eleMatch 数组查询操作符2.1 基本类型数组字段2.2 基本类型数组字段2.3 嵌入式文档数组字段2.4 嵌入式文档数组字段 1. $eq 比较查询操作符 $eq 操作符匹配字段值等于指定值的文档。 db.c…

C++画蜡烛图

GPT-4o (OpenAI) 在 C 中绘制蜡烛图通常不像在高级语言&#xff08;如 Python&#xff09;中那么简单&#xff0c;因为 C 并没有内置的图形绘制库。然而&#xff0c;您可以使用一些第三方库来完成这项任务&#xff0c;比如使用 Qt 或者 SFML 等图形库。这里我们以 Qt 库为例&a…

PM2 快速上手指南

PM2是 Node.js 的优秀运行时管理工具&#xff0c;专为简化和优化 Node.js 应用程序的生产部署与运行而设计。 PM2 官网链接: https://pm2.keymetrics.io/ 1.PM2 的优势 持续运行&#xff1a;即使应用出错或崩溃&#xff0c;也能自动重启。负载均衡&#xff1a;智能地自动分…

Vue常用的指令都有哪些?都有什么作用?什么是自定义指令?

常用指令&#xff1a; 1、v-model 多用于表单元素实现双向数据绑定 (同angular中的ng-model) 2、v-for格式&#xff1a; v-for"字段名in(of)数组json"循环数组或json(同angular中的ng repeat),需要注意从vue2开始取消了$index 3、v-show 4、v-hide 隐藏内容 (同a…

Linux shell编程学习笔记67: tracepath命令 追踪数据包的路由信息

0 前言 网络信息是电脑网络信息安全检查中的一块重要内容&#xff0c;Linux和基于Linux的操作系统&#xff0c;提供了很多的网络命令&#xff0c;今天我们研究tracepath命令。 Tracepath 在大多数 Linux 发行版中都是可用的。如果在你的系统中没有预装&#xff0c;请根据你的…

小练习-将阿拉伯数字转换为罗马数字

键盘输入一个字符串&#xff1a; 1.长度小于等于九 2.只能是数字&#xff0c;将内容转换为罗马数字&#xff08;0转换为"") package example;import java.util.Scanner;public class demo04 {public static void main(String[] args) {//录入字符串Scanner sc ne…

SVM(支持向量机)的基本原理

SVM&#xff08;支持向量机&#xff09;的基本原理 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种监督学习算法&#xff0c;主要用于分类和回归任务。其核心思想是在高维空间中寻找一个最优超平面&#xff0c;以最大化不同类别数据点之间的间隔。在二…

Java核心 - Java中的注释详解及最佳实践

作者&#xff1a;逍遥Sean 简介&#xff1a;一个主修Java的Web网站\游戏服务器后端开发者 主页&#xff1a;https://blog.csdn.net/Ureliable 觉得博主文章不错的话&#xff0c;可以三连支持一下~ 如有疑问和建议&#xff0c;请私信或评论留言&#xff01; 前言&#xff1a; 在…