Redux 使用及基本原理

什么是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>
)

参考

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在uni-app使用vue3使用vuex

在uni-app使用vue3使用vuex 1.在项目目录中新建一个store目录&#xff0c;并且新建一个index.js文件 import { createStore } from vuex;export default createStore({//数据&#xff0c;相当于datastate: {count:1,list: [{name: 测试1, value: test1},{name: 测试2, value: …

从hugging face 下模型

支持国内下载hugging face 的东西 下模型权重 model_id 是红色圈复制的 代码 记得设置下载的存储位置 import os from pathlib import Path from huggingface_hub import hf_hub_download from huggingface_hub import snapshot_downloadmodel_id"llava-hf/llava-v1…

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

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

C++:二维数组的遍历

方式一&#xff1a; #include <vector> #include <iostream> int main() { // 初始化一个2x3的二维向量&#xff08;矩阵&#xff09; std::vector<std::vector<float>> matrix { {1.0, 2.0, 3.0}, // 第一行 {4.0, 5.0, 6.0} // 第二行 };…

企业备份NAS存储一体机

企业文件服务器上的数据、员工电脑里的数据以及NAS存储内数据&#xff0c;需要及时备份&#xff0c;Inforternd存储设备内置了强大的备份服务器功能&#xff0c;无需额外费用&#xff0c;就能轻松将重要数据备份至安全可靠的存储空间中。 无论是GS或GSe 统一存储产品&#xff0…

开放式耳机怎么选?五大2024年口碑销量爆棚机型力荐!

在选购开放式耳机的时候&#xff0c;我们总会因为有太多的选择而陷入两难&#xff0c;又想要一个颜值比较高的&#xff0c;又想要同时兼顾性能还不错的&#xff0c;所以作为测评博主&#xff0c;今天我们就给大家带来自己的一些选购技巧和自己觉得还不错开放式耳机&#xff0c;…

不同行业如何选择适合自己行业的项目管理工具?

在当今的信息化时代&#xff0c;项目管理软件已成为各行各业不可或缺的工具。然而&#xff0c;由于各行业具有不同的特点和需求&#xff0c;因此选择合适的项目管理软件成为了一个重要问题。本文将探讨不同行业在选择项目管理软件时需要考虑的因素&#xff0c;希望能帮助大家更…

python-图像模糊处理(赛氪OJ)

[题目描述] 给定 n 行 m 列的图像各像素点的灰度值&#xff0c;要求用如下方法对其进行模糊化处理&#xff1a; 1. 四周最外侧的像素点灰度值不变。 2. 中间各像素点新灰度值为该像素点及其上下左右相邻四个像素点原灰度值的平均&#xff08;四舍五入&#xff09;输入&#xff…

安卓微商大师V3.4.0/高级版一键群发僵尸粉检测

一款高效获取客源&#xff0c;备受好评的微商工具&#xff0c;资源丰富&#xff0c;秒速获得客源&#xff0c;大量群客源&#xff0c;都是散客&#xff0c;携手创业&#xff0c;是做微商生意的首选工具。打开即是黑钻高级会员 赶快体验吧 很强大 链接&#xff1a;https://pan.…

针对 Windows 10 的功能更新,版本 22H2 - 错误 0xc1900204

最近想帮女朋友生win11发现她电脑安装更新总是卡到安装%10这里失败 原来是安装路径被修改过了&#xff0c;改回c盘 win R → 输入regedit 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion

分布式日志采集 Loki 配置及部署详细

分布式日志采集 Loki 配置及部署详细 Loki 部署模式Loki 读写分离部署配置Loki 配置大全 Loki 部署模式 &#xff08;1&#xff09;可扩展部署模式 Loki 的简单可扩展部署模式是最简单的部署方式、首选方式。可扩展到每天几TB的日志&#xff0c;但是如果超出这个范围&#xff…

线下生鲜蔬果店做小程序有什么方法

生鲜蔬果是生活所需&#xff0c;大小商家众多&#xff0c;零售批发各种经营模式&#xff0c;小摊贩或是超市门店都有着目标客户或准属性群体。竞争和获客转化也促进着商家寻找客源和加快线上进程。 尤其是以微信社交为主的私域场景&#xff0c;普客/会员都需要精细化管理营收和…

WebSocket解决方案(springboot 基于Redis发布订阅)

WebSocket 因为一般的请求都是HTTP请求&#xff08;单向通信&#xff09;&#xff0c;HTTP是一个短连接&#xff08;非持久化&#xff09;&#xff0c;且通信只能由客户端发起&#xff0c;HTTP协议做不到服务器主动向客户端推送消息。WebSocket确能很好的解决这个问题&…

携手共筑爱的桥梁:引导接纳自闭症同学

在孩子的班级中&#xff0c;当自闭症儿童成为我们共同的一员时&#xff0c;作为老师和家长&#xff0c;我们肩负着特别的责任——引导孩子们以开放的心态接纳、善待并关爱他们。 首先&#xff0c;我们要以身作则&#xff0c;展现接纳与尊重。无论是老师还是家长&#xff0c;都…

【计算机网络】计算机网络的分类

计算机网络的分类 导读一、按分布范围分类1.1 广域网&#xff08;WAN&#xff09;。1.2 城域网&#xff08;MAN&#xff09;1.3 局域网&#xff08;LAN&#xff09;1.4 个人区域网&#xff08;PAN&#xff09;1.5 多处理器系统 二、按传输技术分类2.1 广播式网络2.2 点对点网络…

Ajax异步请求 axios

Ajax异步请求 axios 1 axios介绍 原生ajax请求的代码编写太过繁琐,我们可以使用axios这个库来简化操作&#xff01; 在后续学习的Vue(前端框架)中发送异步请求,使用的就是axios. 需要注意的是axios不是vue的插件,它可以独立使用. axios说明网站&#xff1a;(https://www.kancl…

【数据结构】04.双向链表

一、双向链表的结构 注意&#xff1a;这里的“带头”跟前面我们说的“头节点”是两个概念&#xff0c;带头链表里的头节点&#xff0c;实际为“哨兵位”&#xff0c;哨兵位节点不存储任何有效元素&#xff0c;只是站在这里“放哨的”。 “哨兵位”存在的意义&#xff1a;遍历循…

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

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

LLM端侧部署系列 | 手机上运行47B大模型?上交推理框架PowerInfer-2助力AI手机端侧部署

0. 引言 黄梅时节家家雨&#xff0c;青草池塘处处蛙。 有约不来过夜半&#xff0c;闲敲棋子落灯花。 当下&#xff0c;在移动设备上部署大型模型的趋势是愈演愈烈。Google推出了AI Core&#xff0c;使得Gemini Nano可以在智能手机上部署。此外&#xff0c;近期传闻苹果在iOS …

SQL语句(DQL)

Data Query Language&#xff08;数据查询语言&#xff09;&#xff0c;用来查询数据库中表的记录 DQL-基本查询 DQL-条件查询&#xff08;WHERE&#xff09; -- 查询姓名为2个字的员工信息 select * from emp where name like __;-- 查询身份证号最后一位是X的员工信息 selec…