• redux与react-redux的学习笔记之react-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
    
    • 1

    2.原理图

    在这里插入图片描述

    原理图释义

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2)demo
    //redux文件夹下新建constant.js文件
    /* 该模块适用于定义action对象中type类型的常量值
    目的只有一个:便于管理的同时防止单词写错   
     */
    
    export const INCREMENT = 'increment'
    
    export const DECREMENT = 'decrement'
    
    export const SET_OPERATOR = 'setOperator'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    //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)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    //action下新建user_action.js
    import { SET_OPERATOR } from '../constant'
    
    export function setOperator(data){
        return{
            type: SET_OPERATOR,
            data,
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    store.js

    1)含义

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

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

    reducer.js

    1)含义

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

    1)reducer的本质是一个函数,接收:preState,action,发布加工后的状态
    2)reducer有两个作用:初始状态,加工状态
    3)reducer被第一次调用时,是store自动触发的,传递的preState是undefined
    
    • 1
    • 2
    • 3
    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    //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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    //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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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)
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    //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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1)明确两个概念:
        1UI组件:不能使用redux的api,只负责页面的呈现和交互等
        2)容器组件:负责和redux通信,将结果交给UI组件
    2)如何创建一个容器组件---react-redux的connect函数
        connect(mapStateToProps, mapDispatchToProps)(UI组件)
        -mapStateToProps:映射状态,返回值是一个对象
        -mapDispatchToProps:映射操作状态的方法,返回值是一个对象
    3)备注:容器组件中的store是靠props穿进去的,而不是在容器组件中直接引入
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    1)定义一个Person组件,和Count组件通过redux共享数据
    2)为Person组件编写,reducer、action,配置constant常量
    3)重点:Person的reducer和Count的Reducer要使用combineReducer进行合并,合并后的总状态是一个对象
    4)交给store的是总reducer,最后注意在组件中取出状态的时候,记得取到位
    
    • 1
    • 2
    • 3
    • 4
    //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(
    //     
    //       
    //     
    //   );  
    // })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    三、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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    总结

    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.***读取和操作状态
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    RabbitMQ入门教学
    JavaScript之JS事件机制
    Django教程
    【学习笔记】《The Linux Command Line》第一部分 1 - 11 章(shell、进程、重定向、命令等)
    FF14 一些赚金币的小技巧(持续更新中)
    C++前缀和算法的应用:统计得分小于K的子数组数目
    红日靶场复现1
    JAVASE 第二十三天
    Java使用FFmpeg对视频文件打标记
    撰寫自己的Python C擴展!
  • 原文地址:https://blog.csdn.net/chenacxz/article/details/127837231