leiwuhen-67's blog leiwuhen-67's blog
首页
    • 《Vue》笔记
    • 《React》笔记
    • 《NodeJs》笔记
    • 《CSS》笔记
    • 《Redis》笔记
    • 基础入门
    • 《Mock》笔记
    • 《MySQL》笔记
    • 《Git》相关
影音视听
收藏
关于
GitHub (opens new window)

我的公众号

首页
    • 《Vue》笔记
    • 《React》笔记
    • 《NodeJs》笔记
    • 《CSS》笔记
    • 《Redis》笔记
    • 基础入门
    • 《Mock》笔记
    • 《MySQL》笔记
    • 《Git》相关
影音视听
收藏
关于
GitHub (opens new window)
  • React

    • 使用React脚手架快速搭建项目
    • hooks之useEffect
    • React之事件绑定及简写方式
    • React之props传值并对其进行限制
    • React之Refs的基本使用
    • React之生命周期钩子
    • React之key的使用
    • React之代理服务器配置
    • React之封装全局Loading组件
    • React之消息的发布-订阅(pubsub-js)
    • React之Redux的基本使用
    • React之react-redux的基本使用
      • React之redux的数据持久化存储
      • React之路由懒加载
      • React之Render Props的使用
      • React之createBrowserRouter
      • React之路径别名@配置
      • React之craco打包优化配置
      • React之项目国际化
      • React之postcss-pxtorem移动端适配
      • React之使用vite创建项目
      • React之ts类型标注汇总
      • React之使用 ant design搭建后台管理之踩坑
      • React之路由切换动画
      • React之使用vite创建组件库并发布到npm
      • React之项目打包部署到nginx
      • React之自定义组件添加className与style
    • React Native

    • 《React》笔记
    • React
    心欲无痕
    2024-03-21
    目录

    React之react-redux的基本使用

    redux 需要我们手动在 componentDidMount 生命周期中订阅事件来更新 state,那么有没有一款工具能自己监听 state 的变化并自动更新呢?答案当然是有的,那就是 React-Redux,它是 React 官方推出的 redux 绑定库,会自己监听 state 的变化并进行更新。

    # react-redux 的基本使用

    1、安装 react-redux

    npm install react-redux
    
    1

    2、创建 reducer

    // src/store/countReducer.js文件
    const initialState = {
      count: 0
    }
    const countReducer = (state = initialState, action) => {
      switch (action.type) {
        case 'ADD':
        	// 注意,一定要返回一个新对象,否则redux察觉不到数据变化
          return {
            ...state,
            count: state.count + action.data
          }
        case 'MINUS':
          return {
            ...state,
            count: state.count - action.data
          }
        default:
          return state
      }
    }
    
    export default countReducer
    
    
    // 使用createSlice的用法,需要前需要先安装@reduxjs/toolkit => npm install @reduxjs/toolkit
    // import { createSlice } from "@reduxjs/toolkit";
    
    // const countSlice = createSlice({
    //   name: "count",
    //   initialState: {   // 初始值须为对象或数组,否则更改时会报错
    //     count: 0
    //   },
    //   reducers: {
    //     increment: (state, action) => {
    //       state.count += action.payload;  // 这里必须是payload字段,不能换
    //     },
    //     decrement: (state, action) => {
    //       state.count -= action.payload;
    //     },
    //     incrementByAmount: (state, action) => {
    //       state.count += action.payload;
    //     },
    //   }
    // })
    
    // export const { increment, decrement, incrementByAmount } = countSlice.actions;
    // export default countSlice.reducer
    
    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

    3、创建 Redux Store

    // /src/store/index.js
    
    import { createStore, combineReducers } from "redux"
    import countReducer from "./count/countReducer";
    // import userReducer from "./userReducer";
    
    // const reducer = combineReducers({
    //   countReducer,
    //   userReducer
    // })
    export default createStore(countReducer)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    4、为 React 提供 Redux Store

    在 src/index.js 中引入我们刚刚创建的 store , 通过 React-Redux 的 Provider 组件将 App 组件 包裹起来,并将 store 作为 prop 传入

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import store from "./store";
    import { Provider } from 'react-redux'
    
    
    ReactDOM.render(
      <Provider store={store}>
        <App/>
      </Provider>,
      document.getElementById('root')
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    5、创建 Count 组件

    import React from 'react';
    import { useSelector, useDispatch } from "react-redux";
    
    // 这是使用createSlice方法创建reducer,需要如下引入,如果是createStore方式,则无需引入
    import { increment, decrement, incrementByAmount } from "../../store/countReducer";
    
    
    const CountRedux = () => {
        const count = useSelector(state => state.countReducer.count);  // 读取store中的数据
        const dispatch = useDispatch(); // 用于dispatch actions
        const handleAdd = (data) => {
        	// createSlice方法
            dispatch(increment(data));  
    
            // 使用createAction方法
            // dispatch({
            // 	type: "ADD",
            // 	data
            // });
        }
        const handleAddAmount = (data) => {
            dispatch(incrementByAmount(data));
        }
        const handleReduce = (data) => {
            dispatch(decrement(data));
        }
        return (
            <div>
               <p>当前结果:{count}</p>
                <button onClick={() => handleAdd(5)}>加</button>
                <button onClick={() => handleAddAmount(10)}>加10</button>
                <button onClick={() => handleReduce(5)}>减</button>
            </div>
        );
    };
    
    export default CountRedux;
    
    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

    上面虽然完成了 react-redux 实现加法的案例,但是我们用的仍然是之前 redux 的思路去实现,并没有真正用到 react-redux 的精髓,在 react-redux 中,其实是有这样两个概念的,即 UI 组件和容器组件,通过 connect 方法将容器组件与 UI 组件连接起来,然后在 UI 组件中就可以通过 props 来访问状态和操作状态的方法了。

    # react-redux 的完整使用:

    # 1、创建 reducer

    // /src/redux/countReducer.js
    /*
    	Reducer不应该更改原有 state,应该始终返回新的对象,否则,React Redux 觉察不到数据变化。
     */
    const initialState = {
      count: 0
    }
    const countReducer = (state = initialState, action) => {
      switch (action.type) {
        case 'ADD':
        	// 注意,一定要返回一个新对象,否则redux察觉不到数据变化
          return {
            ...state,
            count: state.count + 1
          }
        case 'MINUS':
          return {
            ...state,
            count: state.count - 1
          }
        default:
          return state
      }
    }
    
    export default countReducer
    
    
    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

    # 2、创建 store

    // /src/redux/store.js
    
    /* --------  老版本用法 ---------   */
    
    // 有多个reducer
    import { createStore, combineReducers } from "redux"
    import countReducer from "./countReducer";
    import userReducer from "./userReducer";
    
    const reducer = combineReducers({
      countReducer,
      userReducer
    })
    export default createStore(reducer)
    
    // 单个reducer
    import { createStore } from "redux"
    import countReducer from "./countReducer";
    
    export default createStore(countReducer)
    
    
    
    
    /* --------- 新版本用法 --------- */
    /* 
    	当我们在项目中使用createStore来创建store时,编辑器会有一个删除线,
    	表示这个api是已经废弃的api,并且推荐我们使用configureStore,
    	因此,我们需要安装Redux Toolkit, npm install @reduxjs/toolkit
    	它是Redux官方团队提供的一个工具包,提供了一些实用的工具和函数,以便轻松地编写和组织Redux代码。
    	常用的工具函数:
    	1、createSlice函数:用于创建Redux的slice(片段),
    		包括定义初始状态、定义reducer函数以及生成action creators等功能。
    	2、configureStore函数:用于创建Redux的store对象,并自动集成了一些中间件和插件,
    		包括Redux DevTools插件和redux-thunk中间件。它简化了Redux store的配置和初始化过程。
    */
    import { configureStore } from '@reduxjs/toolkit';
    import countReducer from './countReducer';
    
    const store = configureStore({
        reducer: {
            countReducer
        }
    })
    
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46

    # 3、在 /src/index.js 中引入刚创建的 store,并使用 Provider 包裹 App 组件

    import React, {StrictMode} from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import store from "./redux/store";
    import { Provider } from 'react-redux'
    
    
    ReactDOM.render(
        <StrictMode>
            <Provider store={store}>
                <App />
            </Provider>
        </StrictMode>,
      document.getElementById('root')
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 4、在需要使用 redux 的组件中使用

    import { Component } from "react";
    import { connect } from "react-redux";
    
    class Count extends Component {
     
        render() {
            return (
                <div>
                    <h3>当前结果:{this.props.count}</h3>
                    <button onClick={ () => this.props.add() }>加1</button>
                    <button onClick={ () => this.props.minus() }>减1</button>
                </div>
            );
        }
    }
    
    const mapStateToProps = (state) => {
        return state.countReducer // 多个reduder
        // return state   // 单个reducer
    }
    
    const mapDispatchToProps = (dispatch) => {
        return {
            add: () => {
                dispatch({type: "ADD"})
            },
            minus: () => {
                dispatch({type: "MINUS"})
            }
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Count);
    
    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

    如果将创建 action 的部分抽出来单独为一个文件,如 countActions.js

    export function incrementAction(data) {
      return {
        type: "ADD",
        data
      }
    }
    
    export function decrementAction(data) {
      return {
        type: "MINUS",
        data
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    那么上面使用 redux 的组件就可以这样写:

    import React from 'react';
    import { connect } from "react-redux"
    import { incrementAction, decrementAction } from "../../reactRedux/countActions"
    
    
    const CountRedux = (props) => {
        return (
            <div>
               <p>当前结果:{props.count}</p>
                <button onClick={() => props.handleAdd(5)}>加5</button>
                <button onClick={() => props.handleReduce(10)}>减10</button>
            </div>
        );
    };
    
    /*
    	1、mapStateToProps函数返回的是一个对象
    	2、返回的对象中的key作为传递给UI组件props的key,value作为传递给UI组件props的value
    	3、mapStateToProps用于传递状态
     */
    const mapStateToProps = (state) => {
        return state.countReducer
    }
    
    /*
    	1、matDispatchToProps函数返回的是一个对象
    	2、返回的对象中的key作为传递给UI组件props的key,value作为传递给UI组件props的value
    	3、mapDispatchToProps用于传递操作状态的方法
     */
    const mapDispatchToProps = (dispatch) => {
        return {
            handleAdd: (data) => {
                dispatch(incrementAction(data));
            },
            handleReduce: (data) => {
                dispatch(decrementAction(data));
            }
        }
    }
    
    // 简写形式,mapDispatchToProps的值可以是一个函数,也可以是一个返回action的对象
    // const mapDispatchToProps = {
    //     handleAdd: incrementAction,
    //     handleReduce: decrementAction
    // }
    
    // 使用connect()()创建并暴露一个容器组件
    export default connect(mapStateToProps, mapDispatchToProps)(CountRedux);
    
    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

    # 异步逻辑与数据获取

    在使用 redux 的时候,有时候需要进行异步操作,比如从服务端获取数据后再将这些数据存到 store 中,这时候就可以 dispatch 一个 action,这个 action 是一个函数类型的,这种我们称之为异步 action,正常情况下,我们的 action 应该是一个 object 对象,我们称之为同步 action,而在 redux 中,本身不能处理异步 action,因此,这里需要使用到一个中间件,redux-thunk

    1、安装中间件

    npm install redux-thunk
    
    1

    2、创建保存 type 值的文件和生成 action 的文件

    /* 
    		  /src/redux/count/constant.js代码
    */
    export const GETDATA = 'getData';
    
    
    
    /* 
    			/src/redux/count/count_actions.js代码
    */
    import { GETDATA } from './constant'
    import studentsApi from "../../api/studentsApi";  // 获取学生数据的api
    
    
    // 异步获取学生数据action
    export function studentAction (data) {
      return {
        type: GETDATA,
        data
      }
    }
    
    // 异步获取数据
    export function getDataAction() {
      return async (dispatch) => {
        const response = await studentsApi.getStudents()
        if (response.data) {
          dispatch(studentAction(response.data.data))
        }
        // studentsApi.getStudents().then((res) => {
        //     console.log("res", res)
        //   // dispatch(studentAction(res.data.data))
        // })
      }
    }
    
    
    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

    3、创建 countReducer.js 文件

    import { GETDATA } from "./constant";
    
    const initialState = {
      students: []
    }
    const countReducer = (state = initialState, action) => {
      switch (action.type) {
        case GETDATA:
          return {
            ...state,
            students: action.data
          }
        default:
          return state
      }
    }
    
    export default countReducer
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    4、在创建 store 的地方引入 redux-thunk 中间件,和执行中间件的函数 applyMiddleware

    // /src/redux/store.js
    import { createStore, applyMiddleware } from "redux"
    import countReducer from "./count/countReducer";
    import {thunk} from "redux-thunk";
    
    export default createStore(countReducer, applyMiddleware(thunk))
    
    1
    2
    3
    4
    5
    6

    5、创建 Students.jsx 组件,并使用 redux

    import { Component } from "react";
    import { connect } from "react-redux";
    import { getDataAction } from "../../redux/count/count_actions";
    
    class Students extends Component {
        render() {
            return (
                <div>
                    <h3>学生信息</h3>
                    <ul>
                        {
                            this.props.students.map((item, index) => {
                                return (
                                    <li key={index}>
                                        姓名:{item.name},
                                        年龄:{item.age},
                                        性别:{item.sex}
                                    </li>
                                )
                            })
                        }
                    </ul>
                    <button onClick={ () => this.props.getData() }>获取数据</button>
                </div>
            );
        }
    }
    
    const mapStateToProps = (state) => {
        return state
    }
    
    const mapDispatchToProps = (dispatch) => {
        return {
            getData: () => {
                dispatch(getDataAction())
            }
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Students);
    
    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

    # react-redux 总结

    • 1、两个概念:

      ①、UI 组件:不用任何 redux 的 api,只负责页面的呈现和交互

      ②、容器组件:负责和 redux 通信,将结果交给 UI 组件

    • 2、如何创建容器组件

      靠 react-redux 中的 connect 函数,connect (mapStateToProps, mapDispatchToProps)(UI 组件)

      mapStateToProps:映射状态,返回一个对象

      mapDispatchToProps:映射操作状态的方法,返回值是一个对象,mapDispatchToProps 也可以是一个对象

    • 3、容器组件中的 store 是 props 传递进去的,而不是在容器组件中直接引入的

    编辑 (opens new window)
    上次更新: 7/1/2024, 4:56:33 PM
    React之Redux的基本使用
    React之redux的数据持久化存储

    ← React之Redux的基本使用 React之redux的数据持久化存储→

    Theme by Vdoing
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式