react笔记_11 redux

news2025/1/12 3:59:05

目录

    • redux
      • 定义
      • 使用时机
      • redux基本概念
        • Store
        • State
        • Action
        • reducer
      • redux工作原理
      • 语法
        • [1] 创建Store
          • createStore
          • combineReducers
        • [2]创建并分发action
          • dispatch
          • applyMiddleware
          • 语法
          • 举例说明- 做一个加法运算
          • 执行原理
            • redux-thunk中间件使用
        • [3]创建reducer
          • 语法
          • 渲染过程
        • [4]getState
        • [5]subscribe
        • 举例说明
          • 配置redux
            • [1] 下载
            • [2] 配置
    • react-redux
        • 语法
          • connect
          • Provider组件
          • 监听
          • 配置
            • [1]下载
            • [2]配置

redux

redux中文文档

定义

Redux 是 JavaScript 状态容器,提供可预测化的状态管理 --> 是一个专门做状态管理的js库。
redux并不是react的插件库 --> Redux 除了和 React 一起用外,还支持其它界面库(如angular, vue 等)。 它体小精悍(只有2KB–包括依赖)。

使用时机

  • 不需要使用时
    • 如果你不知道是否需要 Redux,那就是不需要它

    • 只有遇到 React 实在解决不了的问题,你才需要 Redux

    • 简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
  • 需要使用时
    • 若是组件间状态比较复杂,可以使用redux.
      • 比如:某个组件的状态,需要共享
      • 比如:某个状态需要在任何地方都可以拿到
      • 比如: 一个组件需要改变全局状态
      • 比如:一个组件需要改变另一个组件的状态

redux基本概念

Store

Redux为单一数据源。

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。

将state、action、reducer 关联在一起;

State

在 Redux API 中,State指一个唯一的 state 值

  • state 就是Redux 应用的全部状态 即 Redux管理的全部数据,通常为一个多层嵌套的对象。
  • state 由 store 管理
  • 当想要获取state数据时 通过API -> getState 获取。

Action

Action 是一个普通对象,用来表示即将改变 state 的意图

State 是只读的,唯一改变 state 的方法就是触发 action。它是将数据放入 store 的唯一途径。

约定俗成,action 必须拥有一个 type属性,表示动作类型,其他属性由自己决定。

reducer

Reducer 的作用是用于描述action 如何改变 state tree。

Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state

可用于初始化状态、加工状态;

redux工作原理

在这里插入图片描述
从原理图来看 compoents 、Action Creators、 Reducers、Stroe -> 表示组件、action 、reducer都是存在多个,而Stroe是唯一的。

若是仅存在一个组件,根本不需要使用redux,只需要使用组件内部状态管理就可以实现功能。
所以现在假设存在多个组件,组件的数据使用 redux 统一管理。当某个组件想要修改数据时

  • [1] 组件想要修改数据 -> 告诉 Action创建者
  • [2] Action 创建者去创建一个Action动作对象(里面包含干什么、如何干)
  • [3] 通过 dispatch函数将 Action动作对象 派发出去
  • [4] Store(调度者) 接收到action,将action和preState(原来的值)交给 reducer
  • [5] reducer 进行计算 并将计算得到的值 交给 Store
  • [6] 组件想要获取数据时 再通过 getState方法 获取更新后的值

举一个最简单的例子

  • component:客人
  • Action Creators : 服务员
  • dispatch: 点菜宝
  • Store: 老板
  • reducer:厨师

语法

[1] 创建Store

createStore
combineReducers

Store 是通过 createStore 方法创建的

  • (1) 引入createStore
    import { createStore } from 'redux'
    
  • (2) 创建Store
    createStore( reducer )
    
    • 若是仅仅存在一个reducer,我们可以直接引入(值为一个函数)
      import { createStore } from 'redux'
      import numReducer from './numReducer'
      const store =  createStore( numReducer )
      
      此时若是获取state, 得到的值就是 该reducer返回的值,比如numReducer返回值为0,此时通过getState得到的值就是0。
    • 若是存在多个reducer, 就需要通过 combineReducers方法进行reducer合并
      import { createStore, combineReducers } from 'redux'
      import numReduce from './numReduce'
      import countReduce from './countReduce'
      const reduces = {
        num:numReduce,
        count:countReduce
      }
      const store =  createStore( combineReducers(reduces) )
      
      此时若是获取state, 得到的值就是 一个对象
      {
        num:numReduce函数的返回值,
        count:countReduce函数的返回值
      }
      

[2]创建并分发action

dispatch
applyMiddleware

使用Action Creator 去创建Action,使用dispatch去派发action。

语法

action的值可以是一个对象,也可以是一个函数

  • 若是值为一个对象 表示是同步更新数据
      {
        type: 动作指令(String类型)data:  操作数据
      }
    
  • 若是值为一个函数 表示是异步更新数据
    // 该方法默认会将dispatch作为函数传入
    (dispatch)=>{
      setTimeOut(()=>{
        dispatch({type:动作指令,data:  操作数据})
      },0) // 使用定时器模拟异步操作
    }
    
举例说明- 做一个加法运算
  • 同步加法
    • action
      export const addAction = data => ({type:INCREMENT,data})
      
    • 在组件中派发此action
      import {addAction} from '../../../store/action.js
      import store from '../../../store'
      // 派发
      store.dispatch(addAction( value ))'
      
  • 异步加法
    • action
      export const addActionAsync = (data, time) =>{
        return (dispatch)=>{
          setTimeout(()=>{
            dispatch({type:'add',data})
          },time)
        }
      }
      
    • 在组件中派发action
       import {addActionAsync} from '../../../store/action.js
       import store from '../../../store'
       // 派发
       store.dispatch(addActionAsync( value ))'
      
执行原理

当使用dispatch去派发action时,在Store会接收到-> Stroe会去查看action的类型

  • 若是类型为一个对象 -> Store会将action交给 reducer

  • 若是类型为一个函数 -> 会报错
    在这里插入图片描述
    希望得到的值为一个对象。
    若是希望action能够兼容值为函数的情况(也就是能够使用异步Action),需要使用一个中间件 redux-thunk

  • 使用redux-thunk中间件后,若是类型为一个函数 -> store会调用该函数并将dispatch 方法作为参数传入(而不会交给reducer)

redux-thunk中间件使用
  • 作用:可以让sotre识别 函数类型的action
  • 使用
    • [1] 下载
      使用命令npm i redux-thunk 下载
    • [2] 配置
      因为我们的目的是想让Stroe能够识别 函数类型的action,所以在store创建过程进行配置 -> 使用applyMiddleware配置中间件
      import { createStore, applyMiddleware } from 'redux'
      const store = createStore(
      // 合并
      combineReducers(reducers),
      // 中间件
      applyMiddleware(Thunk)
      )
      

[3]创建reducer

语法
const init = 初始化的值 // 若是不设置,第一次渲染时默认为undefined
export default function( preState=init, action ){
  const {type, data} = action
  switch (type){
    case type值匹配:
      // 匹配后的逻辑处理
      return 新的state值
    ...
    default:
      return preState
  }
}
渲染过程
  • 在第一次进入页面时 会默认调用所有的reducer, 此时传入的 preState值为
    undefined
    
    默认传入的action值为
    {
      type:@@init... // 后面拼接随机字符
    }
    
  • 后面每次通过dispatch派发action时都会调用对应的reducer

[4]getState

作用:用于获取数据
语法

import { createStore } from 'redux'
const store = createStore(reducer)

store.getState() // 获取数据

[5]subscribe

作用:用于监听redux中状态的变化,只要变化,就会走subscribe函数;
原因: redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己来;
语法

import { createStore } from 'redux'
const store = createStore(reducer)

store.subscribe(()=>{
  console.log('逻辑代码-> 更新数据')
})

举例说明

下面示例的编写的前提是了解redux的API的基础之上,若是没有了解过,可以结合下方的 API一起看;
在这里插入图片描述

现在有如上示例

  • 第一个:num的值;
  • 第二个:操作数,可以选择为1、2、3
  • 第三个:按钮,点击num的值变为 当前值+操作数
  • 第四个:按钮,点击num的值变为 当前值-操作数
  • 第五个:按钮,点击若是当前num的值为偶数->无变化;若是当前num的值为奇数-> num的值变为 当前值+操作数;
  • 第六个:按钮,点击异步增加num的值

若是值存储在当前组件的state中,代码如下

import React, { Component } from 'react'
export default class New extends Component {
 state = { num: 0 }
 render() {
   const { num } = this.state
   return (
     <div>
       {num}
       &nbsp;
       &nbsp;
       <select ref={this.getref}>
         <option value='1'>1</option>
         <option value='2'>2</option>
         <option value='3'>3</option>
       </select>
       &nbsp;
       <button onClick={()=>{this.calculate('increment')}}>+</button>&nbsp;
       <button onClick={()=>{this.calculate('decrement')}}>-</button>&nbsp;
       <button onClick={()=>{this.calculate('incrementIfOdd')}}>和为基数再加</button>&nbsp;
       <button onClick={()=>{this.calculate('incrementAsync')}}>异步加</button>&nbsp;
     </div>
   )
 }
 getref = (dom) => {
   this.select = dom
 }
 calculate = (type)=>{
   // 获取到select选择的值
   const { value } = this.select
   const { num } = this.state
   switch (type){
     case 'increment':
       this.setState({num: num + +value})
       break;
     case 'decrement':
       this.setState({num: num - +value})
       break;
     case "incrementIfOdd":
       if(num % 2 != 0){
         this.setState({num: num + +value})
       }
       break;
     case 'incrementAsync':
       setTimeout(()=>{
         this.setState({num: num + +value})
       }, 100)
   }
 }
}
配置redux
[1] 下载

使用命令npm install --save redux下载redux

[2] 配置
  • (1)在src文件夹下创建一个store文件夹
  • (2) 在store文件夹下创建一个index.js文件 -> 创建store并导出
    import { createStore ,combineReducers,applyMiddleware} from 'redux'
    import reducers from './reduces'
    import Thunk from 'redux-thunk'
    export default createStore(
      combineReducers(reducers), // 合并reducer
      applyMiddleware(Thunk) // 配置中间件
    )
    
  • (3) 在store 文件夹下创建一个reducers文件夹(因为reducer可以有多个),有多少个reducer就在reducers文件夹下创建多少个文件
    • num的reducer -> num.js
      // num默认值为0
      import {INCREMENT, DECREMENT} from '../static'
      export default function( preState=0, action ){
        const {type, data} = action
        switch (type){
          case INCREMENT:
            return preState + data
          case DECREMENT:
            return preState - data
          default:
            return preState // 初始化的时候type为 @@init...
        }
      }
      
    • 集成到reduces文件夹下的index.js文件中
      // 将所有定义的数据发导入到这个对象中然后返回
      
      import numReduce from './num'
      
      const reducers = {
        num: numReduce // 这个值将会作为创建的state中数据的属性名‘num’
      };
      
      export default reducers;
      
  • (4)在store 文件夹下创建一个actions文件夹(因为action可以有多个),有多少组action就在actions文件夹下创建多少个文件
    • 有关num的action -> num.js
      // action可以是一个对象 也可以是一个函数
      // 若是action 为一个对象表示同步更新数据,action为一个函数表示异步更新数据
      import {INCREMENT, DECREMENT} from '../static'
      export const addAction = data => ({type:INCREMENT,data})
      export const decreaseAction = data => ({type:DECREMENT,data})
      export const addActionAsync = (data, time) =>{
        return (dispatch)=>{
          setTimeout(()=>{
            dispatch(addAction(data))
          },time)
        }
      }
      
    • 集成action到actions文件夹下的index.js中
      import { addAction, decreaseAction, addActionAsync } from './numAction'
      
      export {
        addAction,
        decreaseAction,
        addActionAsync
      }
      
  • (5)创建static.js文件 -> 用于保存action的动作指令
     // 指令
     export const INCREMENT = 'increment' // 加法运算
     export const DECREMENT = 'decrement' // 减法运算
    

react-redux

由于很多开发者都喜欢在react中使用redux, Facebook就开发了 react-redux。
react-redux将组件分为 容器组件UI组件

  • UI组件只负责页面的呈现,交互等;在UI组件中不能使用任何关于Redux的API;
  • 容器组件是真正与Redux打交道的,里面可以随意使用Redux的API,最终将结果交给UI组件;
  • 所有的UI组件都应该包裹一个容器组件,他们是父子关系;
  • 容器组件是连接 UI组件 与 Redux的桥梁,容器组件会传递给UI 组件
    • Redux中所保留的状态;
    • 用于操作Redux的方法;
      在这里插入图片描述

语法

connect

connect用于创建一个容器组件

import {connect} from 'react-redux';
export default connect(function1,function2)(UI组件)
  • connect为一个函数

      connect( 
        state=> {
          return 对象 // return的对象的key ,value将添加在UI组件的props中
        }, 
        dispatch =>{
          return 对象 // return的对象的key ,value将添加在UI组件的props中
        }
      )
    

    参数1(mapStateToProps): 是一个回调函数

    • 该函数是 react-redux 调用,该函数在调用时会将state作为参数传入
    • 函数的返回值为一个对象 ,作为UI组件接收的props- 状态

    参数2(mapDispatchToProps): 是一个回调函数

    • 该函数是 react-redux 调用,在调用时会将dispatch 方法作为参数传入
    • 函数的返回值为一个对象,作为UI组件接收的props- 操作状态的方法

    返回值:connect函数的返回值也是一个函数

    • 调用时将 UI组件 作为参数传入
    • 最终得到的值是一个容器组件

注意点:在使用容器组件时需要将 store作为prop传入

  <Count  stroe={ store }/>

在UI组件中接收-> 在props中除了接收 connect中接收的两个方法的返回值还有默认的store的属性和方法

Provider组件

若是我们有多个组件 ,每次都需要在容器组件传递 store,而且若是组件不是普通组件而是路由组件还不好传递,此时就可以使用Provider组件

// [1] 引入组件
import { Provider } from 'react-redux'
import store from './store'
// [2] 包裹跟组件
<Provider store={store}>
   <App/>
</Provider>

Provide组件会去查看项目里哪些组件为容器组件 将 store 传递

监听

redux是 redux只负责管理状态,至于状态的改变驱动着页面的展示是需要我们自己控制的

若是使用了react-redux,就不需要自己监听了,当状态改变时会自动渲染对应的UI组件

配置
[1]下载

使用命令 npm i react-redux 下载react-redux;

[2]配置

对于上面例子的改进

import React, { Component } from 'react'
import {addAction, decreaseAction, addActionAsync} from '../../../store/actions/index'
import {connect} from 'react-redux'
class New extends Component {
  render() {
    const { numReduce } = this.props
    return (
      <div>
        {numReduce}
        &nbsp;
        &nbsp;
        <select ref={this.getref}>
          <option value='1'>1</option>
          <option value='2'>2</option>
          <option value='3'>3</option>
        </select>
        &nbsp;
        <button onClick={()=>{this.calculate('increment')}}>+</button>&nbsp;
        <button onClick={()=>{this.calculate('decrement')}}>-</button>&nbsp;
        <button onClick={()=>{this.calculate('incrementIfOdd')}}>和为基数再加</button>&nbsp;
        <button onClick={()=>{this.calculate('incrementAsync')}}>异步加</button>&nbsp;
      </div>
    )
  }
  getref = (dom) => {
    this.select = dom
  }
  calculate = (type)=>{
    // 获取到select选择的值
    const { value } = this.select
    const { numReduce,  add, decrease, addAsync} = this.props
    switch (type){
      case 'increment':
        add( +value )
        break;
      case 'decrement':
        decrease( +value )
        break;
      case "incrementIfOdd":
        if(numReduce % 2 != 0){
          add( +value )
        }
        break;
      case 'incrementAsync':
        addAsync( +value , 2000 )
    }
  }
}

export default connect(
  state => {
    return state
  },
  dispatch => {
    return {
      add(value){
        dispatch(addAction( value ))
      },
      decrease(value){
        dispatch(decreaseAction(value))
      },
      addAsync(value,time){
        dispatch(addActionAsync(+value, time))
      }
    }
  }
)(New)


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

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

相关文章

基于meanshift算法的目标聚类和目标跟踪matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 meanshift算法其实通过名字就可以看到该算法的核心&#xff0c;mean&#xff08;均值&#xff09;&#xff0c;shift&#xff08;偏移&#xff09;&#xff0c;简单的说&#xff0c;也就是有一个…

Web前端105天-day63-HTML5_CORE

HTML5CORE03 目录 前言 一、复习 二、SVG 三、Echarts 四、Webworker 五、回调地狱 六、Promise 七、promiseajax 八、promise_axios 九、async_await 总结 前言 HTML5CORE03学习开始 一、复习 跨域 浏览器的同源策略限定: 网页中利用 AJAX 请求数据, 必须访问同源…

【CSS】flex布局用法解析,快速上手flex布局,flex:1是什么意思?肯定看的懂好吧?

一、flex布局 flex 是 flexible box 的缩写&#xff0c;意为"弹性布局"&#xff0c;用来为盒状模型提供最大的灵活性。 任何一个容器都可以指定为 flex 布局。 采用 flex 布局的元素&#xff0c;称为 flex 容器&#xff08;flex container&#xff09;&#xff0c;…

如何解决跨越

解决跨域我想在坐的各位都会听说过几个解决跨域的方法&#xff1a; 1.有什么 cors后端配置&#xff08;加几个请求头 2.jsonp&#xff08;利用script的src属性&#xff09; 3.还有vue-cli前端配置。 跨域其实就是违背了浏览器的一种策略&#xff0c;这种策略就是同源策略&…

公司刚来的阿里p8,看完我构建的springboot框架,甩给我一份文档

前言&#xff1a; 我们刚开始学习 JavaWeb 的时候&#xff0c;使用 Servlet/JSP 做开发&#xff0c;一个接口搞一个 Servlet &#xff0c;很头大&#xff0c;后来我们通过隐藏域或者反射等方式&#xff0c;可以减少 Servlet 的创建&#xff0c;但是依然不方便&#xff0c;再后…

【Transformer】医学分割领域的应用与扩展(论文阅读)(二) || DETR

声明:仅学习使用~ 目录 1. Transformer学习2. DETR1. Transformer学习 前篇指路:【Transformer】医学分隔领域的应用与扩展(论文阅读)(一) 继续… 关于Self-Attention的公式: 原来是 m x m 是2D的,现在变成1 x m了,是1D的了。 下图中。左图是传统的Transformer,右…

【python圣诞树的实现】

&#x1f935;‍♂️ 个人主页老虎也淘气 个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f44d;&#x1f3fb; 收藏…

拒不外传,阿里内部耗重金找人总结出这份并发编程手册(全彩版)

并发世界很有趣&#xff0c;不要错过 前言&#xff1a; 时间飞逝&#xff0c;转眼间毕业七年多&#xff0c;从事 Java 开发也六年了。我在想&#xff0c;也是时候将自己的 Java 整理成一套体系。 这一次的知识体系面试题涉及到 Java 知识部分、性能优化、微服务、并发编程、开…

python常用模块

time模块 常用操作 1.直接获取时间 time.time() #获取结果是秒数&#xff0c;即从1970年1月1日8:00起计#1671856010.9592516 2.获取结构化时间 time.localtime() #获取本地时间&#xff0c;中国为东八区&#xff0c;为上海时间 time.gmtime() …

C++控制台圣诞树

前言 有是一年圣诞节&#xff0c;先祝大家圣诞节快乐&#xff0c;所以本蒟蒻在AFO之后决定回来更新一篇打印字符圣诞树的教程 &#xff08;呃好吧我承认我就是想嫖奖品&#xff09; 效果展示 呃我知道这有点拉&#xff0c;但是……蒟蒻能有什么坏心思呢&#xff0c;他只不过想…

客户端服务端交互实现

问题 客户端业务逻辑如何实现&#xff1f; 与服务设备具体交互细节如何设计&#xff1f; 客户端业务逻辑实现 用户输入处理 字符串空格处理&#xff0c;分割获取命令与参数 服务信息处理 字符串预处理&#xff0c;分割获取服务命令存储服务命令与设备地址之间的映射(命令字…

Java Socket实现NIO通信

文章目录一.简单介绍通道&#xff08;Channel&#xff09;多路复用器&#xff08;Selector&#xff09;二.代码实现.客户端服务端运行结果一.简单介绍 NIO 很多人也称之为 Non-block I/O&#xff0c;即非阻塞 I/O&#xff0c;因为这样叫&#xff0c;更能体现它的特点。 为什么…

kdump功能

kdump功能前言1 kdump流程2 kdump配置2.1 kexec、makedumpfile编译2.2 系统内核2.3 捕获内核3 kdump测试4 kdump的不足前言 kdump 是一种先进的基于 kexec 的内核崩溃转储机制。当系统崩溃时&#xff0c;kdump会将内存导出为vmcore保存到磁盘。 在kernel1运行的时候&#xff…

RabbitMQ——延迟队列

目录 一、延迟队列的应用场景 1. 场景&#xff1a;"订单下单成功后&#xff0c;15分钟未支付自动取消" ① 传统处理超时订单 ② RabbitMQ延时队列方案 二、延迟队列中的消息投递和消息消费 1.TTL 和 DLX ① TTL ② DLX和死信队列 ③ 延迟队列 ④ 开发步骤 …

spring mvc 通过异常封装 验证 方法

正常情况 我们先演示一下正常情况下我们验证的方法。 首先定义一个LoginBean Data public class LoginBean {// Blank 不允许保存空格&#xff0c;空格不算内容NotBlank(message "用户名不能为空")String username;// Empty 允许保留空格&#xff0c;是空格也算内容…

【Spring】核心部分之AOP:通过列举代码例子,从底层刨析,深入源码,轻轻松松理解Spring的核心AOP,AOP有这一篇足以

AOP基本概念基本原理专业术语案例演示基于注解&#xff08;重点&#xff09;基于配置文件基本概念 面向切面编程&#xff0c;也叫面向方面编程&#xff0c;利用aop可以对业务逻辑的各个部分进行隔离&#xff0c;从而使得业务逻辑各个部分之间降低耦合&#xff0c;提高程序的可…

AQS 对资源的共享方式

AQS 定义两种资源共享方式 1) Exclusive&#xff08;独占&#xff09; 只有一个线程能执行&#xff0c;如 ReentrantLock。又可分为公平锁和非公平锁,ReentrantLock 同时支持两种锁,下面以 ReentrantLock 对这两种锁的定义做介绍&#xff1a; 下面来看 ReentrantLock 中相关的…

概要设计说明书(GB8567——88)基于协同的在线表格forture-sheet

概要设计说明书 1引言 1.1编写目的 为了帮助用户更好的了解和使用本在线表格&#xff0c;提高用户与软件的亲和度。 用户手册描述配置和使用改在线表格&#xff0c;以及该软件使用过程中应该注意的一下问题。 1.2背景 说明&#xff1a; 本用户手册所描述的软件系统的名称…

医疗检测数据存储管理系统

摘要 医疗信息化的迅速发展导致了医疗数据的指数型增长&#xff0c;医疗检测数据存储管理系统给医院现有信息系统带了巨大的压力。一方面,随着各种非结构化数据的不断涌现&#xff0c;现有的医疗信息系统在存储空间&#xff0c;存储速度、存储结构上达不到医疗检测数据的要求,不…

Github惊现神作,这份算法宝典让你横扫各大厂算法面试题

时间飞逝&#xff0c;转眼间毕业七年多&#xff0c;从事 Java 开发也六年了。我在想&#xff0c;也是时候将自己的 Java 整理成一套体系。 这一次的知识体系面试题涉及到 Java 知识部分、性能优化、微服务、并发编程、开源框架、分布式等多个方面的知识点。 写这一套 Java 面试…