redux与react-redux的学习笔记之react-redux

news2025/4/7 1:34:14

redux与react-redux

  • 前言
  • 一、redux和react-redux是啥?
  • 二、redux使用步骤
    • 1.引入库
    • 2.原理图
      • 原理图释义
      • actions
        • 1)含义
        • 2)demo
      • store.js
        • 1)含义
        • 2)demo
      • reducer.js
        • 1)含义
        • 2)demo
      • Count.jsx
        • 1)含义
        • 2)demo
      • Person.jsx
  • 三、redux开发者工具的使用
  • 总结


前言

工作中Vue为主,React使用逐渐生疏,对redux仅达到会用的地步。偶尔遇到React项目,用到redux也就是把别人写过的东西重写一遍,最近有时间去B站白嫖了一下 React教程。写个笔记记录下!!!


一、redux和react-redux是啥?

redux是 JavaScript 状态容器,提供可预测化的状态管理,是一个独立的库可以搭配UI框架进行使用。
与redux稍加不同的是,react-redux是 React 的官方 Redux UI 绑定库,可以订阅 store、检查更新数据和触发重新渲染的过程可以变得更加通用和可复用。
简单的说,react-redux最终还是使用redux去取数据,不过是封装一层方便使用redux的api。
相对于Vuex的简单无脑操作,这两个算是稍微麻烦一点的。不过后续阿里封装了个hox,使用起来感觉简单了很多。

二、redux使用步骤

1.引入库

代码如下(示例):

npm install react-redux

2.原理图

在这里插入图片描述

原理图释义

1.所有的UI组件都应该包裹一个容器组件,他们是父子关系
2.容器组件是真正和redux打交道的,里面可以随意的使用redux的api
3.UI组件不能使用任何redux的api
4.容器组件会传给UI组件:1)redux中所保存的状态,2)用于操作状态的方法
5.备注:容器给UI传递:状态、操作状态的方法,均通过props传递

actions

1)含义

Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。

action返回的是Object类型的叫做同步action
action返回的是Function类型的叫做异步 action
异步action:
(1).明确:延迟的动作不想交给组件自身,想交给action
(2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回(非必须)
(3).具体编码:
    1).cnpm i redux-thunk,并配置在store中,//行驶转换程序
    2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务
    3).异步任务有结果后,分发一个同步的action去真正的操作数据
(4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果再去分发同步action

2)demo

//redux文件夹下新建constant.js文件
/* 该模块适用于定义action对象中type类型的常量值
目的只有一个:便于管理的同时防止单词写错   
 */

export const INCREMENT = 'increment'

export const DECREMENT = 'decrement'

export const SET_OPERATOR = 'setOperator'
//redux文件夹下新建action文件夹
//action下新建count_actions.js
/*
 该文件专门为Count组件生成求和count_actions对象   
 */

import {INCREMENT, DECREMENT} from '../constant'

export const incrementAction = (data) => ({ type: INCREMENT, data })//同步action
//同步action,就是指action的返回值为Object类型的一般对象
export function decrementAction(data){   
    return {     
        type: DECREMENT, 
        data   
    }//返回的是一个对象,普通数据类型,同步action,返回对象为异步
}
//异步action,就是指action的返回值为函数
//异步action中,一般都会调用同步action,异步action不是必须要用的
export const incrementAsyncAction = (data, time) => {
    return (dispatch)=>{//返回对象为异步action
        setTimeout(()=>{
            dispatch(incrementAction(data))
        }, time)
    }
}
//action下新建user_action.js
import { SET_OPERATOR } from '../constant'

export function setOperator(data){
    return{
        type: SET_OPERATOR,
        data,
    } 
}

store.js

1)含义

store是一个状态管理器,是一个仓库,存储公共的状态数据。Redux 应用只有一个单一的 store

1)引入redux中的createStore函数,创建一个store
2)createStore调用时要传入一个为其服务的reducer
3)记得暴露store对象
4)  redux只负责管理状态,至于状态的改变驱动着页面的展示要靠我们自己写

2)demo

//redux文件夹新建store.js
//引入creacteStore,专门用于创建redux中最核心的store对象,applyMiddleware执行中间件
import { legacy_createStore as createStore, applyMiddleware} from "redux";
//引入redux-thunk用于支持异步action
import thunk from 'redux-thunk'
//引入为组件服务的reducer
import rootReducers   from './reducers'
const store  = createStore(rootReducers, applyMiddleware(thunk))
//暴露出去
export default store

reducer.js

1)含义

Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。

1)reducer的本质是一个函数,接收:preState,action,发布加工后的状态
2)reducer有两个作用:初始状态,加工状态
3)reducer被第一次调用时,是store自动触发的,传递的preState是undefined

2)demo

//redux文件夹下新建reducers文件夹
//新建count_reducer.js
import {INCREMENT, DECREMENT} from '../constant'
//监测提交过来的action,preState是前一条数据,初始化时默认为0
const counter = (preState = 0,action)=>{
    const {type, data}= action
    switch(type){
        case INCREMENT:
            return preState + data;
        case DECREMENT:
            return preState - data;
        default:
            return preState;
    }
}

export default counter;
//redux文件夹下新建reducers文件夹
//新建user_reducer.js
import { SET_OPERATOR } from '../constant'

const operator = (preState = {}, action)=>{
    const {type, data}= action
    switch(type){
        case SET_OPERATOR:
            return Object.assign(preState, data);
        default :
            return preState
    }
}

export default operator;
//redux文件夹下新建reducers文件夹
//新建index.js

import { combineReducers } from 'redux';
import counter from './count_reducer';
import operator from './user_reducer'

// 合并多个 reduce
const rootReducers = combineReducers({
    counter:counter,
    operator:operator
});

export default rootReducers;

Count.jsx

1)含义

操作组件,里面包含数据加减,和数据赋值两个功能

2)demo

//引入Count的UI组件
// import CountUI from '../../components/Count'
//引入action  
import { 
    incrementAction, 
    decrementAction, 
    incrementAsyncAction 
} from '../../redux/actions/count_actions'
//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
// import store from '../../redux/store'
import React, { Component } from 'react'
import store from '../../redux/store'

import { setOperatorAction } from '../../redux/actions/user_action'

class Count extends Component {
    state = {
        
    }
    
    //加
    increment=()=>{
        const {value}=this.selectNumber
        this.props.increment(value*1)
    }
    //减
    decrement=()=>{
        const { value } = this.selectNumber
        this.props.decrement(value*1)
    }
    //当前求和的数据为奇数再加
    incrementIfOdd=()=>{
        const counter = this.props.count.counter
        const { value } = this.selectNumber
        if(counter % 2 !=0) {
            this.props.increment(value*1)
        }
        
    }
    //异步加
    incrementAsync=()=>{
        const { value } = this.selectNumber
        this.props.incrementAsync(value*1, 1000)
    }
    addUserInfo = () => {
        const operator = {
            name: '大黄'+Math.floor(Math.random()*100),
            age: Math.floor(Math.random()*100)
        }
        this.props.setOperator(operator)
    }   
    render() {
        console.log(this.props)
        return (
            <div> 
                <h2>Person数组的长度{this.props.personLen.length}</h2>
                <h1>当前求和为{this.props.count}</h1>
                <select ref={c=>this.selectNumber =c}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button onClick={()=>{this.increment()}}>+</button>
                <button onClick={()=>{this.decrement()}}>-</button>
                <button onClick={()=>{this.incrementIfOdd()}}>如果为奇数</button>
                <button onClick={()=>{this.incrementAsync ()}}>异步增加 </button>
            </div>
        )
    }
}
//a函数的返回对象的key就作为传递给UI组件props的key,value就作为传递给UI组props的value---状态
const mapStateToProps = (state)=> ({count: state.counter, personLen: state.operator})
//b函数的返回对象的key就作为传递给UI组件props的key,value就作为传递给UI组props的value---操作状态的方法
//一般写法 
// const mapDispatchToProps = (dispatch)=> ({
//     increment: (number)=> dispatch(incrementAction(number)),
//     decrement: (number)=> dispatch(decrementAction(number)),
//     incrementAsync: (number)=> dispatch(incrementAsyncAction(number, 2000)),
// })
//高级写法
//因为用了react-redux能够自动dispatch
const mapDispatchToProps = {
    increment: incrementAction,
    decrement: decrementAction,
    incrementAsync: incrementAsyncAction,
    setOperator: setOperatorAction
}
//创建一个容器组件
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(Count)
//暴露容器组件
export default CountContainer;

//export default connect()(CountUI)
  
//App.js
import Count from './container/Count'
import Person from './container/Person'
// import store from './redux/store'
function App() {
  return (
    <div className="App">
      <Count/>
      <hr/>
      <Person/>
    </div>
  );
}

export default App;


1)明确两个概念:
    1UI组件:不能使用redux的api,只负责页面的呈现和交互等
    2)容器组件:负责和redux通信,将结果交给UI组件
2)如何创建一个容器组件---react-redux的connect函数
    connect(mapStateToProps, mapDispatchToProps)(UI组件)
    -mapStateToProps:映射状态,返回值是一个对象
    -mapDispatchToProps:映射操作状态的方法,返回值是一个对象
3)备注:容器组件中的store是靠props穿进去的,而不是在容器组件中直接引入

Person.jsx

//引入Count的UI组件
// import CountUI from '../../components/Count'
//引入action  
//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
// import store from '../../redux/store'
import React, { Component } from 'react'
import { setOperatorAction } from '../../redux/actions/user_action'

class Count extends Component {
    state = {
        
    }
    addUserInfo = () => {
        const name = this.nameNode.value
        const age = this.ageNode.value
        const personObj = {id: Math.floor(Math.random()*100), name, age}
        this.props.setOperator(personObj)
        this.nameNode.value = ''
        this.ageNode.value = ''
        console.log(name, age)
    }   
    render() {
        console.log(this.props.operator, this.props.count)
        return (
            <div> 
                <h2>Person组件,Count组件的总和为{this.props.count}</h2>
                <div>
                    <input ref={c=> this.nameNode= c} type="text" placeholder="输入名字"/>
                    <input ref={c=> this.ageNode= c} type="text"  placeholder="输入年龄"/>
                    <button onClick={()=>{this.addUserInfo()}}>添加用户信息</button>
                    <ul>
                        {
                            this.props.operator.map(item=>{
                                return <li key={item.id}>{item.name}---{item.age}</li>
                            })
                        }
                    </ul>
                </div>
            </div>
        )
    }
}
//a函数的返回对象的key就作为传递给UI组件props的key,value就作为传递给UI组props的value---状态
const mapStateToProps = (state)=> ({operator: state.operator, count: state.counter})
//高级写法
//因为用了react-redux能够自动dispatch
const mapDispatchToProps = {
    setOperator: setOperatorAction
}
//创建一个容器组件
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(Count)
//暴露容器组件
export default CountContainer;

//export default connect()(CountUI)
  
1)定义一个Person组件,和Count组件通过redux共享数据
2)为Person组件编写,reducer、action,配置constant常量
3)重点:Person的reducer和Count的Reducer要使用combineReducer进行合并,合并后的总状态是一个对象
4)交给store的是总reducer,最后注意在组件中取出状态的时候,记得取到位
//index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import store from './redux/store'
import App from './App';
import {Provider} from 'react-redux'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
   /*给容器组件传递store */
  <Provider store={store}>
    <App />
  </Provider>
);  
// 监听redux中状态的变化,如果redux的状态发生了变化,
//那么重新渲染App组件
//react-redux不用再监测了
// store.subscribe(() => {
//   root.render(
//     <Provider store={store}>
//       <App />
//     </Provider>
//   );  
// })

三、redux开发者工具的使用

npm i redux-devtools-extension
store文件
//引入redux-devtools-extension
import { composeWithDevTools } from 'redux-devtools-extension'

// const store  = createStore(rootReducers, composeWithDevTools())
const store  = createStore(rootReducers, composeWithDevTools(applyMiddleware(thunk)))

总结

1)容器组件和UI组件整合成一个文件
2)无需自己给容器组件传递store,给<App/>包裹 <Provider store={store}>即可
3)使用了react-redux无需自己检测redux中状态的变化,容器组件可以自动完成这个工作
4)mapDispatchToProps也可以简写成一个对象
5)一个组件要和redux打交道要经过几步?
    1)定义好UI组件---不暴露
    2)引入connect生成一个容器组件,并暴露,写法如下:
        connect(state=>(
            {key:value},//映射状态
        ),
        {
            key:action//映射操作状态的方法
        })UI组件中通过this.props.***读取和操作状态

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

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

相关文章

2022年,我们为什么要学习C++?

“C已死” 大学时代&#xff0c;我就听过这样的说法——差不多十多年前的事儿了。那时候至少在美国&#xff0c;Java已经成了各公司的主流语言。程序员也许都很熟悉Joel Spolsky在2005年12月对JavaSchools发起的批驳。此外&#xff0c;作为微软应对Java的手段&#xff0c;2000…

Ubuntu环境配置(instant-ngp)

综合环境配置 这篇文章的综合配置我是在恒源云上配的&#xff0c;自己穷买不起机子&#xff0c;就只能租咯&#xff0c;这家价格还行&#xff0c;而且可以装VNC&#xff0c;非推广&#xff0c;只是感觉方便&#xff0c;请大家结合自身实际情况 数据上传 这里有几种方法&…

【免费】多种方法手把手教你如何将自己做的网页做成网络链接(直接访问)

目录 前言 ​一、github&#xff08;最常用的&#xff09; 二、七牛云&#xff08;推荐小白使用&#xff0c;简单粗暴&#xff09; 三、NATAPP 四、codepen&#xff08;建议学网页的人群使用&#xff09; 彩蛋 前言 http://t.csdn.cn/VaiP1我之前发的爱心代码&#xff0c;…

电脑突然开机无反应,怎么办

电脑常见故障之三开机无响应&#xff08;上&#xff09; 经常使用电脑的朋友应该会碰到这种情况&#xff0c;开机时按下电源按钮后&#xff0c;电脑无响应&#xff0c;显示器黑屏不亮。 除去那些傻瓜式的故障原因&#xff0c;如显示器、主机电源没插好&#xff1b;显示器与主…

手写小程序摇树优化工具(一)——依赖分析介绍

道可道&#xff0c;非常道&#xff1b;名可名&#xff0c;非常名&#xff1b;玄之又玄&#xff0c;众妙之门。 现在国内好像没有什么针对小程序代码的摇树优化方案&#xff0c;出现了很多超包的问题无法解决&#xff0c;本教程就手把手教大家如何编写一个完整的微信小程序摇树优…

深度学习零基础学习之路——第四章 UNet-Family中Unet、Unet++和Unet3+的简介

Python深度学习入门 第一章 Python深度学习入门之环境软件配置 第二章 Python深度学习入门之数据处理Dataset的使用 第三章 数据可视化TensorBoard和TochVision的使用 第四章 UNet-Family中Unet、Unet和Unet3的简介 Unet-Family的学习Python深度学习入门前言一、FCN全卷积网络…

【JavaSE】面向对象三大特性之多态

文章目录多态的概念向上转型重写之动态绑定与重载之静态绑定重写与重载的区别重写的注意事项总结不安全的向下转型多态的优点和注意事项优点缺点和注意事项多态的概念 多态可以理解为一个对象在某些时刻可以代表不同的对象&#xff0c;指的是对象的多种形态。所以在某些时刻&a…

CSDN第九次竞赛题解与总结

CSDN第九次竞赛题解与总结前言T1小艺读书题意分析T2鬼画符门之宗门大比题意分析代码别的方法T3硬币划分题意分析状态转移方程初始值代码T4饿龙咆哮-逃离城堡题意分析坑点代码写在最后前言 2022/11/12 我有幸参加了csdn第九次竞赛&#xff0c;终于拿了次满分&#xff0c;进了次…

Vuex④(多组件共享数据、Vuex模块化+namespace)

文章目录多组件共享数据代码实现Vuex模块化总结多组件共享数据 我们现在想实现这种情况&#xff1a; Person组件的总人数就是Person中列表的长度 br上的是Count组件&#xff0c;br下的是Person组件。 我们通过vuex中的state实现一些数据的多组件共享&#xff1a; 代码实现 …

第二章STP应用配置

目录 一 生成树 二 生成树算法 三 STP是什么 四 BPDU是什么 五 BPDU的概念 六 生成树基本配置 一 生成树 生成树算法的网桥协议STP(Spanning Tree Protocol) 它通过生成生成树保证一个已知的网桥在网络拓扑中沿一个环动态工作。网桥与其他网桥交换BPDU消息来监测环路&#xf…

使用 hugo oss 搭建个人博客网站

系列文章目录 文章目录系列文章目录前言一、下载hugo二、oss三、域名四、创建博客上传五、发布&#xff0c;上传文章前言 本文主要详解如何用最低的成本搭建个人博客网站 原本我是直接用的github搭建的博客网站&#xff0c;因为免费&#xff0c;但由于github访问很不稳定&…

Python——正则表达式的应用

文章目录前言正则表达式方法re.search方法group方法re.match方法re.findall方法re.finditer方法re.split方法re.sub方法正则表达式的应用前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 正则表达式是字符串处理的有力工具和技术。 使用正在表达式的目的…

多态(polymorphic)

目录 1. 多态的基本介绍 2. 多态实现条件 3. 重写 重写的介绍&#xff1a; 【重写和重载的区别】 动、静态绑定机制 5 向上转型和向下转型 向上转型 向上转型的特点&#xff08;总结&#xff09;&#xff1a; 向下转型 多态的优缺点 多态是Java三大基本特征中最抽象…

【数据结构初阶】数组栈和链式队列的实现

努力真的要贯穿人的一生吗&#xff1f; 你能活成你想要的样子吗&#xff1f; 真的不知道&#xff01; 文章目录一、栈的概念及结构二、栈的实现&#xff08;动态数组栈&#xff09;2.1 挑选实现栈的结构2.2 栈结构的定义2.3 初始化栈销毁栈2.4 入栈出栈2.5 判空取栈顶元素栈元…

Android Studio App开发之循环试图RecyclerView,布局管理器LayoutManager、动态更新循环视图讲解及实战(附源码)

运行有问题或需要全部源码请点赞关注收藏后评论区留言~~~ 一、循环视图RecyclerView 尽管ListView和GridView分别实现了多行单列和多行多列的列表&#xff0c;使用也很简单&#xff0c;可是它们缺少变化&#xff0c;风格也比较呆板&#xff0c;为此Android推出了更灵活多变的循…

CAS:1347750-20-2,NH2-PEG-SH,Amine-PEG-Thiol,氨基-聚乙二醇-巯基供应

1、名称 英文&#xff1a;NH2-PEG-SH&#xff0c;Amine-PEG-Thiol 中文&#xff1a;氨基-聚乙二醇-巯基 2、CAS编号&#xff1a;1347750-20-2 3、所属分类&#xff1a; Amine PEG Thiol PEG 4、分子量&#xff1a;可定制&#xff0c;5000、氨基-聚乙二醇 1000-巯基、1000、…

云计算———虚拟化技术镜像的构建及Harbor的使用(三)

一、容器管理 1.1容器命令 docker ps &#xff1a;查看正在运行的容器 &#xff0c;已经关闭的不能查看 docker ps -a&#xff08;显示所有容器&#xff09; 可以 docker -f rm MyWordPress&#xff1a;-f 强制删除容器 [rootlocalhost ~]# docker ps -a -q #显示所有容器只…

java项目-第127期SpringBoot+vue的智慧养老手表管理系统-java毕业设计_计算机毕业设计

java项目-第127期SpringBootvue的智慧养老手表管理系统-java毕业设计_计算机毕业设计 【源码请到资源专栏下载】 本系统主要是通过智能手表监控老人的日常生活&#xff0c;比如血压、心率、睡眠步数、以及摔倒情况。 共分为两个角色&#xff1a;家长&#xff0c;养老院管理员&a…

有含金量的AI证书

文章目录证书展示企业认证介绍华为认证人工智能工程师课程内容我的总结和资料证书展示 这是华为云的AI认证&#xff1a; 这是阿里云的大数据认证&#xff1a; 企业认证介绍 一般的企业是办不起来认证的&#xff0c;大家肯定都知道的。本文主要介绍华为云的认证&#xff0c…

经典动态规划:最长递增子序列

力扣第300题&#xff1a;[最长递增子序列]&#xff0c;这道题是非常经典的动态规划和二分查找的题目&#xff0c;我们先看dp: 第一种解法&#xff1a;动态规划 我们先看题目的示例1&#xff1a; 输入&#xff1a;nums [10,9,2,5,3,7,101,18] 输出&#xff1a;4 解释&#x…