Redux 使用及基本原理

news2025/1/12 6:47:12

什么是Redux

Redux 是用于js应用的状态管理库,通常和React一起用。帮助开发者管理应用中各个组件之间的状态,使得状态的变化变得更加可预测和易于调试。
Redu也可以不和React组合使用。(通常一起使用)

Redux 三大原则

单一数据源

  • 整个应用程序的state被存储在一棵obj tree中,这个obj tree只存储在一个store中;
  • redux 并没有强制让我们不能创建多个Store,但这样做不利于数据的维护;
  • 单一的数据源可以让整个应用程序的state变得方便维护,追踪,修改。

State是只读的

  • 唯一修改state的方法是触发action
  • 这样确保了View或网络请求都不能直接修改state,他们只能通过action来描述自己想要如何修改state;
  • 可以保证所有修改都被集中化处理,并按照严格的顺序来执行,所以不必担心race condition的问题。

使用纯函数来执行修改

  • 通过reducer将旧state和actions联系在一起,返回一个新的State
  • 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree 的一部分
  • 但所有的reducers都应该是纯函数,不能产生任何的副作用。
    在这里插入图片描述

redux 如何使用

  1. 安装react-redux:
    yarn add react-redux
  2. 创建store 管理全局状态

src/store/constants.js

export const ADD_NUMBER = 'add_number'
export const SUB_NUMBER = 'sub_number'
export const CHANGE_BANNERS = 'change_banners'
export const CHANGE_RECOMMENDS = 'change_recommends'

创建reducer管理状态

src/store/reducers.js

import * as actionTypes from "./constants"

const initialState = {
  counter: 100,
  banners: [],
  recommends: []
}
function reducer(state = initialState, action) {
  switch (action.type) {
    case actionTypes.ADD_NUMBER:
      return { ...state, counter: state.counter + action.num }
    case actionTypes.SUB_NUMBER:
      return { ...state, counter: state.counter - action.num }
    case actionTypes.CHANGE_BANNERS:
      return { ...state, banners: action.banners }
    case actionTypes.CHANGE_RECOMMENDS:
      return { ...state, recommends: action.recommends }
    default:
      return state
  }
}
export default reducer

src/store/index.js

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(reducer);

export default store;

src/store/actionCreators.js
创建actionCreators,放修改状态的函数

import * as actionTypes from "./constants"
import axios from "axios"

export const addNumberAction = (num) => ({
  type: actionTypes.ADD_NUMBER,
  num
})

export const subNumberAction = (num) => ({
  type: actionTypes.SUB_NUMBER,
  num
})


export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners
})

export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends
})



export const fetchHomeMultidataAction = () => {
  // 如果是一个普通的action, 那么我们这里需要返回action对象
  // 问题: 对象中是不能直接拿到从服务器请求的异步数据的
  // return {}

  return function(dispatch, getState) {
    // 异步操作: 网络请求
    // console.log("foo function execution-----", getState().counter)
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      const banners = res.data.data.banner.list
      const recommends = res.data.data.recommend.list

      // dispatch({ type: actionTypes.CHANGE_BANNERS, banners })
      // dispatch({ type: actionTypes.CHANGE_RECOMMENDS, recommends })
      dispatch(changeBannersAction(banners))
      dispatch(changeRecommendsAction(recommends))
    })
  }

  // 如果返回的是一个函数, 那么redux是不支持的
  // return foo
}
  1. 在项目index.js 根节点引用
    src/index.js
import {Provider} from 'react-redux'
import store from 'react-redux'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
	<React.StrictMode>
		<Provider store={store}>
			<App />
		</Provider>
	</React.StrictMode>
);
  1. 在需要使用redux的页面或组件中,通过connect高阶组件映射到该组件的props中,解耦store和class组件的耦合。
    在这里插入图片描述

redux中异步操作

redux也引入了中间件的概念:

  • 目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码
  • 比如日志记录,调用异步接口,添加代码调试功能等

发送异步网络请求,可以添加对应的中间件

  • 官网推荐 redux-thunk

redux-thunk 如何可以发送异步请求

  • 默认情况下的dispatch(action),action需要是一个js对象
  • redux-thunk可以让dispatch(action函数),action可以是一个函数
  • 该函数会被调用,并会传给这个函数一个dispatch函数和getState函数
  • dispatch函数用于我们之后再次派发action
  • getState 函数考虑我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态

如何使用redux-thunk

  1. 安装redux-thunk
    yarn add redux-thunk
  2. 创建store时传入应用了middleware的enhance函数
  • 通过applyMiddleware来结合多个Middleware,返回一个enhancer;
  • 将enhancer作为第二个参数传入到createStore中;
// 通过applyMiddleware来结合多个Middleware, 返回一个enhancer
const enhancer = applyMiddleware(thunkMiddleware);
// 将enhancer作为第二个参数传入到createStore中
const store = createStore(reducer, enhancer);
  1. 定义返回一个函数的action:
  • 注意:这里返回一个函数
  • 该函数在dispatch之后会被执行
const getHomeMultidataAction = () => {
  return (dispatch) => {
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      const data = res.data.data;
      dispatch(changeBannersAction(data.banner.list));
      dispatch(changeRecommendsAction(data.recommend.list));
    })
  }
}

combineReducers函数

  • 事实上,redux给我们提供了一个combineReducers函数可以让我们方便对多个reducer进行合并
  • 那么combineReducers是如何实现的?
    • 它也是将我们传入的reducers合并到一个对象中,最终返回一个combination函数(相当于我们之前的reducer函数)
    • 在执行combination函数的过程中,它会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state。
    • 新的state会触发订阅者发生对应的刷新,而旧的state可以有效的组织订阅者发生刷新。

Redux 基本原理

所有的状态都以对象树的方式(state)存放于单个store中。
唯一改变状态树(state tree)的方法是创建action:一个描述发生了什么的对象,并将其dispatch派发给store。要指定状态树如何响应action来进行更新,你可以编写纯reducer函数,这些函数根据旧的state和action来计算新state。
新的state被创建后,对象会自动传递给所有注册了监听器的组件,从而触发组件的重新渲染,使得界面始终保持与当前的state对象一致。
在这里插入图片描述
在这里插入图片描述

Redux在React中具体的使用方法

官方建议,安装其他两个插件 Redux Toolkit和React-Redux

  1. React Toolkit(RTK):官方推荐编写Redux逻辑的方式,是一套工具的集合,简化书写方式
  2. React-Redux:用来链接 Redux和React组件的中间件
    在这里插入图片描述
  3. 安装方式
    npm install @reduxjs/toolkit react-redux

Redux Toolkit(RTK)

1. createSlice 函数

作用:创建一个Redux的slice。它接受一个包含reducer函数,slice名称和初始状态的配置对象,并返回一个包含reducer和action creators的对象。
参数

  • name:slice的名称,用于标识状态的一部分。
  • initialState:slice的初始状态,定义了状态的初始值‘
  • reducers:一个对象,包含一组同步的reducer函数,用于更新状态。
    返回值:
    createSlice 返回一个包含以下属性的对象:
  • name:slice的名称
  • reducer:一个reducer 函数,用于处理来自action creators的动作并更新状态
  • actions:一组action creators,用于创建派发给reducer的动作。

栗子 🌰:

import { createSlice } from '@reduxjs/toolkit';

// 定义初始状态
const initialState = {
  count: 0,
};

// 创建一个 Redux slice
const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    // 定义同步的 reducer 函数
    increment(state) {
      state.count += 1;
    },
    decrement(state) {
      state.count -= 1;
    },
    // 可以接受额外参数的 reducer 函数
    incrementByAmount(state, action) {
      state.count += action.payload;
    },
  },
});

// 导出action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// 导出reducer
export default counterSlice.reducer;

上述代码使用 createSlice 函数创建一个名为 counter 的slice。包含一个名为 count的状态和三个同步的reducer函数:increment,derement和incrementByAmount。

  • 通过increment,decrement,incrementByAmount 派发动作
    通过counterSlice.reducer 处理动作

configureStore 函数

作用:创建一个Redux store,它接受一个包含reducer函数和其他配置选项的对象,并返回一个Redux store 实例。
参数

  • reducer:一个或多个reducer函数,用于处理来自action creators 的动作并更新状态
  • 其他配置选项:包括 middleware,devTools 等,用于配置store的行为。
    返回值
  • configureStore 返回一个Redux store 实例,它包含以下属性和方法:
    • getState():用于获取当前的状态
    • dispatch(action):用于派发一个动作,以触发状态的更新
    • subscribe(listener):用于添加一个状态变化的监听器,当状态发生变化时会被调用
    • replaceReducer(nextReducer):用于替换当前的reducer

栗子🌰:

import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers'; // 导入根 reducer

// 创建 Redux store
const store = configureStore({
  reducer: rootReducer,
  // middleware: getDefaultMiddleware => getDefaultMiddleware(), // 使用默认的中间件
  // devTools: process.env.NODE_ENV !== 'production', // 在开发环境启用 Redux DevTools
});

export default store

在栗子中,我们使用configureStore 函数创建了一个Redux store
我们传入了一个根reducer rootReducer,它是一个包含所有reducer的对象。我们还配置了默认的中间件,并在开发环境下启用了Redux DevTools。

react-redux

它将所有组件分为两大类:UI 组件和容器组件。

  1. UI 组件:负责呈现页面(React)
  2. 容器组件:负责管理数据和业务逻辑(Redux)

react-redux中常用的组件及方法

Provider 组件

作用:将Redux的store 传递给整个React应用程序,使得所有组件都能够访问到redux的状态。通过provider,我们可以在任何地方使用redux的状态和派发动作。

好处:在整个应用程序中,任何一个组件都可以通过connect函数或useSelector钩子函数来访问Redux store 中的状态,而不需要手动将store传递给每一个组件。

  • 简化代码:不需要在每一个组件中手动传递store,通过Provider,store可以在整个应用程序中自动传递给需要的组件。
  • 避免prop drilling:避免了在组件层级结构中进行多层次的prop 传递,提高了代码的可维护性和可读性。
  • 一致性:所有的组件都使用相同的redux store,保证了应用程序状态的一致性。
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

import store from './store';
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <Provider store={store}>
      <App />
    </Provider>
)

参考

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

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

相关文章

图书馆书籍管理系统

项目名称与项目简介 图书馆书籍管理系统 本项目是一个计算机管理系统&#xff0c;也就是将传统手工的管理方式转变为智能化、标准化、规范化的管理管理模式&#xff0c;对图书馆中所有的图书、文献资料、音像资料、报刊、期刊等各种类型的资料实现采编、收集图书信息、检索、归…

【笔记】强化学习,gym的命令行图形化界面适配

搞了一大堆还是搞不出来放弃了 最后用matplotlib画出来看 import gym import matplotlib.pyplot as plt from IPython import display import numpy as np %matplotlib inlineenv gym.make(CartPole-v1, render_mode"rgb_array") observation env.reset() a 0 f…

JWT入门

JWT与TOKEN JWT&#xff08;JSON Web Token&#xff09;是一种基于 JSON 格式的轻量级安全令牌&#xff0c;通常用于在网络应用间安全地传递信息。而“token”一词则是一个更广泛的术语&#xff0c;用来指代任何形式的令牌&#xff0c;用于在计算机系统中进行身份验证或授权。J…

EIOT能源物联网平台在连锁门店的应用

在当今快节奏的商业环境中&#xff0c;连锁门店的管理和运营变得越来越具有挑战性。能源数据是连锁门店的管理中重要组成部分&#xff0c;为了提高门店的能源利用效率和管理水平&#xff0c;需要依赖先进的集团能源管理系统&#xff0c;进而实现节能减排&#xff0c;优化运营成…

探索指针(3)-C语言

目录 1.字符指针变量 一. 什么是字符指针&#xff1f; 二.字符指针的使用 三.常量字符串与字符指针的关系 四.字符数组和字符串常量 2.数组指针变量 一. 指向数组的指针 3. 二维数组传参的本质 指针形式的函数参数 4.函数指针变量 一. 函数指针的声明 二. 初始化和…

常见锁策略之可重入锁VS不可重入锁

可重入锁VS不可重入锁 有一个线程,针对同一把锁,连续加锁两次,如果产生了死锁,那就是不可重入锁,如果没有产生死锁,那就是可重入锁. 死锁 我们之前引入多线程的时候不是讲了一个加数字的案例么,我们今天以它来举例 当我们这样写的时候会出现什么问题? 分析:第一个synchron…

alibaba EasyExcel 简单导出数据到Excel

导入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.1</version> </dependency> 1、alibaba.excel.EasyExcel导出工具类 import com.alibaba.excel.EasyExcel; import …

揭秘,PyArmor库让你的Python代码更安全

PyArmor 概述: PyArmor 是一个用于加密和保护 Python 源代码的工具,旨在防止代码被逆向工程和未经授权的使用.通过将 Python 源代码编译为加密的字节码,PyArmor 提供了一种有效的方法来保护知识产权和敏感算法. 安装 pip install pyarmor安装完成后,可以通过以下命令验证安装…

SaaS联盟分销系统如何高效管理推广渠道的实用指南

随着众多SaaS企业不断向PLG模式转型&#xff0c;传统的推广方式&#xff0c;比如广告投放推流、第三方cookie数据追踪等方式的成本效益比低下&#xff0c;更多的SaaS企业选择可“低成本&#xff0c;高回报”的联盟营销策略。比如Figama、Unbounce、Looka这些中小型SaaS企业&…

SCI丨5分期刊,JCR一区

SCI&#xff0c;5分&#xff0c;JCR Q1&#xff0c;中科大类3小类2区 1 基于复杂网络与xxx能源汽车节能数值分析 2 基于热能损失优化的xxx与性能管理 3 基于xxxLCA技术的绿色制造工艺优化研究 4 基于xxx入侵检测技术的物联网智能制造监控系统设计 6 基于物联网技术xxx电力系…

鸿蒙认证值得考吗?

鸿蒙认证值得考吗&#xff1f; 鸿蒙认证&#xff08;HarmonyOS Certification&#xff09;是华为为了培养和认证开发者在鸿蒙操作系统&#xff08;HarmonyOS&#xff09;领域的专业技能而设立的一系列认证项目。这些认证旨在帮助开发者和企业工程师提升在鸿蒙生态中的专业技能…

通过混合栅极技术改善p-GaN功率HEMTs的ESD性能

来源&#xff1a;Improved Gate ESD Behaviors of p-GaN PowerHEMTs by Hybrid Gate Technology&#xff08;ISPSD 24年&#xff09; 摘要 本工作中&#xff0c;首次证明了混合栅极技术在不增加额外面积和寄生效应的前提下&#xff0c;能有效提升p-GaN HEMTs的栅极静电放电(E…

刷代码随想录有感(124):动态规划——最长公共子序列

题干&#xff1a; 代码&#xff1a; class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {vector<vector<int>>dp(nums1.size() 1, vector<int>(nums2.size() 1, 0));int res 0;for(int i 1; i <…

[单master节点k8s部署]16.监控系统构建(一)Prometheus介绍

prometheus prometheus是继k8s之后&#xff0c;第二个被托管到CNCF的项目&#xff0c;是一个开源的监控报警系统。 1.prometheus支持多维数据模型&#xff0c;每一个时间序列数据都由metric度量指标名称和它的标签label组成一组键值对。 2.Prometheus有自己的PromQL查询语言…

mac|Mysql WorkBench导入文件失败(修改编码)

⚠️&#xff1a;表格中有中文的不适用表格中有中文的不适用表格中有中文的不适用表格中有中文的不适用 我有一个excel表&#xff0c;想导入到mysql数据库中&#xff0c;但是Workbench的导入格式只支持csv&#xff0c;通过excel、wps将excel另存为csv文件进行导入 导入会因为编…

Swift 中强大的 Key Paths(键路径)机制趣谈(下)

概览 在上一篇博文 Swift 中强大的 Key Paths(键路径)机制趣谈(上)中,我们介绍了 Swift 语言中键路径机制的基础知识,并举了若干例子讨论了它的一些用武之地。 而在本文中我们将再接再厉,继续有趣的键路径大冒险,为 KeyPaths 画上一个圆满的句号。 在本篇博文中,您将…

高考服务系统

摘 要 每年有大批考生在进行填写高考志愿时并不很清楚自己的高考分数适合那些高校以及专业。高考考生面临着未被高校录取&#xff0c;被调剂专业&#xff0c;甚至可能复读的问题。若能让考生轻松查询到高校录取、高校专业、高校招生等相关信息&#xff0c;能减少很大一部分考生…

2007-2023年36家商业银行绿色信贷、期末贷款总额、银行总资产等相关指标数据(2023年无缺失)

2007-2023年36家商业银行绿色信贷数据&#xff08;2023年无缺失&#xff09; 1.时间&#xff1a;2007-2023年&#xff0c;2023年无缺失 2.来源&#xff1a;银行年报和社会责任报告 3.指标:绿色信贷余额、期末贷款总额、绿色信贷比率、总资产收益率、流动性比率、拨备覆盖率、…

svn忽略上传文件node_modules文件

文章目录 1.点击svn项目右键-》选中svn的属性2. 点击 新建3. 点击其他4. 选择属性 svn:global-ignores5. 输入忽略文件 1.点击svn项目右键-》选中svn的属性 2. 点击 新建 3. 点击其他 4. 选择属性 svn:global-ignores 5. 输入忽略文件

通信软件开发之业务知识:PON口割接什么意思?

一 PON口割接&#xff08;原创总结&#xff09; 在通信领域&#xff0c;PON口割接指的是对无源光网络&#xff08;Passive Optical Network&#xff0c;PON&#xff09;端口进行的切换或调整操作。简单来说&#xff0c;就是对光纤网络中的某个端口进行重新连接或重新分配&…