• 【Redux 和 React-Recux】


    一、Redux

    Redux:是一个状态管理的库。不是React内置的,是独立的JavaScript的状态容器,提供可预测的状态管理。在React中使用Redux,可以把所有的state集中到组件的顶部,能够灵活地将所有的state分发给所有的组件。方便了开发者管理React中的状态,也方便了不同组件间的通信

    1、三大核心

    • store:是一个数据容器,用来管理和保存整个项目的state。整个项目中只能有一个store
    • state:是一个对象,在state中存储相应的数据,当开发者需要使用数据时,可以通过store提供的方法来获取state
    • action:是一个通知命令,用于对state进行修改。通过store提供的方法可以发起一个动作(action)完成对state的修改

    2、Redux的函数

    (1)action:本质是JavaScript对象,在action中包含一个字符串类型的type属性,作用是指定要对state进行何种操作
    action会通过store将要进行的操作传给reducer函数,由reducer完成对state的修改

    action({type:'add',data:''})
    
    • 1

    (2)reducer:是一个纯函数。有两个参数state和action。该函数一定有一个返回值,是修改后的state。

    纯函数:

    a、纯函数在执行过程中没有任何的副作用。如定时器、网络请求。
    b、如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部状态或数据的变化。

    function reducer(state = { count:1},action) {
    			 
    	   switch(action.type){
    					
    		   case 'ADD':
    					   
    	          return { count:state.count+1 }
    						  
    			case 'SUB':
    						
    			  return { count:state.count-1 }
    		}		 
    			  return state;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    (3)createStore:用于创建store,参数必须是reducer,reducer函数名可以自定义

    3、store对象提供的方法

    (1)getState:用来获取state

    (2)dispatch(action):派发动作(action)给reducer

    (3)subscribe(listener):会注册一个监听器来监听state的变化。会返回一个注销监听器的方法 。 Redux的工作模式:发布-订阅模式

    举例:利用Redux实现计数器

    💥举例:利用Redux实现计数器

    index.js(自定义的js文件): 创建纯函数和一个状态容器

    
    //版本问题createStore已修改为legacy_createStore,但可以通过以下形式修改成简单写法
    import {legacy_createStore as createStore} from "redux";
    
    //创建一个纯函数:
    function reducer(state={count:1},action){
        console.log('Action'+action.type);
    
        switch (action.type){
            case 'ADD':
                return{count:state.count+1};
            case 'SUB':
                return{count:state.count-1}
            default:
                return state;
        }
    }
    
    //2.创建状态的容器:store
    let store = createStore(reducer);
    
    //3.导出store
    export default store;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Counter.jsx代码段:

    import React from "react";
    //导入数据的状态容器store
    import store from "../store";
    class Counter extends React.Component{
        constructor(props) {
            super(props);
            this.state = {  //定义组件自己的状态
                number:store.getState().count  //将容器中的state的count值赋给自己的状态属性
            }
        }
    
        //组件挂载之前进行订阅
        componentDidMount() {
            this.unSubScribe = store.subscribe(()=>{
                this.setState({
                    number:store.getState().count
                })
            })
        }
    
        //组件卸载时取消订阅
        componentWillUnmount() {
            this.unSubScribe && this.unSubScribe()  //如果订阅了store,就取消订阅
        }
    
        render(){
            return(
                <>
                    <p>{ this.state.number}</p>
                    <button onClick={()=>{ store.dispatch({type:'ADD'})}}>1</button>
                    &nbsp;&nbsp;&nbsp;&nbsp;
                    <button onClick={()=>{ store.dispatch({type:'SUB'})}}>1</button>
                </>
            )
        }
    }
    export default Counter;
    
    
    • 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

    App.js:

    import logo from './logo.svg';
    import './App.css';
    import Counter from "./components/Counter";
    
    function App() {
        
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              Edit <code>src/App.js</code> and save to reload.
            </p>
          </header> 
            <Counter/>
        </div>
      );
    }
    
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    4、在组件(类组件)中使用redux的过程

    (1)安装:npm install redux

    (2)通过store的getState()方法获取store中状态属性的值

    (3)通过store的dispatch方法向纯函数派送动作

    (4)通过store的subscribe方法对store进行订阅

    具体使用方法参考上一个示例

    5、Redux使用的缺点

    每个组件在使用时都要引入store,当组件嵌套时,整个操作会非常麻烦

    二、React-Recux

    1、特点

    (1)是React官方的绑定库

    (2)可以实现所有组件共享store

    (3)虽然是React官方的绑定库,但使用时仍然需要安装(npm i react-redux),通常要和redux结合使用。

    2、组成部分

    (1)Provider组件:作用是将store共享给包含在中的所有子组件

    <Provider store={ 用户定义的store} >    // store是Provider组件的属性
    			
    	 <App/>
    			   
    </Provider>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    含义:将用户定义的’store’共享给App的所有子组件

    (2)connect组件/函数:是一个React定义的高阶组件。所谓的高阶组件就是给它传入一个组件,它会返回新的加工后的组件

    connect(state=>newProps)(Component)
    
    • 1

    connect函数的参数:

    mapStateToProps:本质是一个函数,用来监听store的state的变化,一旦发现state发生了改变,该函数就就会自动执行。

    mapDispatchToProps:用来获取action并派送action

    3、在类组件的使用

    index.jsx: 创建纯函数和一个状态容器

    import {legacy_createStore as createStore} from "redux";
    
    function reducer(state={count:1},action){
        switch (action.type){
            case'ADD':
                return {count:state.count + 1}
            case'SUB':
                return {count:state.count - 1}
            default:
                return state
    
        }
    }
    
    let store = createStore(reducer);
    export default store;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    index.js(全局配置文件): 将自定义的store共享给了App及其子组件

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css';
    import App from './App';
    import {Provider} from 'react-redux'
    import store from './store'
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
        <Provider store={ store }>  {/*将自定义的store共享给了App及其子组件*/}
            <App />
        </Provider>
    );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    action.js:

    function add(){
        return {
            type:'ADD'
        }
    }
    
    function minus(){
        return {
            type:'MINUS'
        }
    }
    
    const action = {add,minus}
    
    export default action;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Counter.jsx

    import React from "react";
    import {connect} from 'react-redux'
    import action from "../store/action";
    
    class Counter extends React.Component{
        render() {
            return (
                <div>
                    <p>{ this.props.count }</p>
                    <button onClick={ this.props.add}>1</button>
                    &nbsp;&nbsp;&nbsp;&nbsp;
                    <button onClick={this.props.minus}>1</button>
                </div>
            )
        }
    }
    
    const mapStateToProps = state=> state; //获取store的state并传递给props
    const mapDispatchToProps = {...action}  //获取action并派发出去
    
    //通过connect函数将共享的store和定义好的action传递给Counter组件的props属性
    
    export default connect(mapStateToProps,mapDispatchToProps)(Counter);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    App.js:

    import logo from './logo.svg';
    import './App.css';
    import Counter from "./components/Counter";
    
    function App(props) {
        return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
          </header>
            <Counter/>
        </div>
      );
    }
    export default App;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    4、在函数组件中使用

    (1)在React-Redux7.x以后的版本中增加了用于操作React-Redux的Hooks,这些hooks只能在函数组件中使用
    (2)组成部分:

           A、const state = useSelector(state=>state),功能类似于connect
    	   
    	   B、const dispatch = useDispatch(),返回store中的dispatch方法
    	   
    	   C、const store = useStore(),返回的是store
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其余配置遇上一个示例相同

    Counter1.jsx代码段:

    import React from "react";
    
    import { useDispatch,useSelector} from "react-redux";
    
    function Counter1(props){
        const count = useSelector(state=>state.count)
        const dispatch = useDispatch();
    
        return (
            <div>
                <p>{ count } </p>
                <button onClick={()=>{ dispatch({type:'ADD'})}}>1</button>
                <button onClick={()=>{ dispatch({type:'MINUS'})}}>1</button>
            </div>
        )
    }
    export default Counter1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    三、reducer的拆分与合并

    1、拆分

    一个项目只有一个store,为了便于维护可以将reducer按照模块进行拆分

    例如:User(用户数据)、Todo(待办事项)
    function userReducer(state={},action){}
    function todoReducer(state={},action){}
    
    • 1
    • 2
    • 3

    2、合并

    在创建store时将reducer进行合并。使用的方法是combineReducer({})

    const store = createStore(combineReducer({user,todo}))
    
    • 1

    四、redux-thunk中间件

    1、中间件(middleware):Redux的核心操作比较简单。在实际的开发中,当action派发之后,reducer操作之前还要做一些其他的工作。由于reducer是一个纯函数,这些额外的工作他无法完成,所以需要一个中间件。

    2、redux-thunk中间件:主要用于解决项目中的异步请求
    (1)安装:npm i react-redux
    (2)创建store时,引入中间件,redux提供了applyMiddleware来引入
    (3)利用中间件完成额外工作

  • 相关阅读:
    一文看懂 Python 中的函数参数
    为什么说 Gradle 是 Android 进阶绕不去的坎 —— Gradle 系列(1)
    大数据ClickHouse(八):MergeTree系列表引擎之MergeTree(重点掌握)
    Qt 使用RAW INPUT获取HID触摸屏,笔设备,鼠标的原始数据,最低受支持的客户端:Windows XP [仅限桌面应用]
    Windows安装CMake详细教程(附学习资料)
    MySQL存储架构
    400电话怎么办理(申请开通)
    【Spring容器的启动过程】
    双编码器构建机器人零力拖动/导纳控制思路
    当new一个对象时在JVM中会有哪些操作
  • 原文地址:https://blog.csdn.net/fcc627/article/details/126498574