React学习之路 - React与Redux

一 Redux的快速上手

Redux是React最常用的集中状态管理工具(类似于Vue的Vuex), 它是可以独立于框架运行

作用: 通过集中管理的方式, 管理应用的状态

初体验

html 复制代码
    <body>
        <button id="decrement"> - </button>
        <span id="count">0</span>
        <button id="increment"> + </button>
    </body>
  1. 定义reducer函数
  2. 通过 Redux.createStore()创建store实例
  3. 通过store.subscribe()订阅数据的变化
  4. 通过store.dispatch()触发action, 修改数据
  5. 使用store.getState()获取最新数据
js 复制代码
<script>
        // 获取dom
        let inBtn = document.querySelector('#increment'),
            deBtn = document.querySelector('#decrement'),
            count = document.querySelector('#count');

        // 1. 定义reducer函数
        function reducer(state = { count: 1 }, action){
            // state 状态  action: 触发的条件
            if(action.type === 'INCREMENT'){
                // 加 逻辑
                return {
                    count: state.count + 1
                }
            }else if(action.type === 'DECREMENT'){
                // 减 逻辑
                return {
                    count: state.count - 1
                }
            } else {
                return state
            }
        }

        // 2. 通过 Redux.createStore()创建store实例
        let store = Redux.createStore(reducer);

        // 3. 通过store.subscribe()订阅数据的变化
        store.subscribe(() => {
            // 5. 使用store.getState()获取最新数据
            count.innerHTML = store.getState().count;
        })

        // 绑定点击事件
        inBtn.addEventListener('click', function () {
            // 4. 通过store.dispatch()触发action, 修改数据
            store.dispatch({
                type: 'INCREMENT'
            })
        });
        deBtn.addEventListener('click', function () {
            store.dispatch({
                type: 'DECREMENT'
            })
        });
</script>

二 环境准备

在React中使用redux, 需要安装两个插件 Redux Toolkitreact-redux

  • Redux Toolkit(RTK) - 官方推荐编写Redux逻辑的方式,是一套工具集, 简化Redux的书写方式
  • react-redux - 连接React 和 Redux的中间件
  1. 使用CRA快速创建React项目

npx create-react-app react-redux

  1. 安装配套工具

npm i @reduxjs/toolkit react-redux

  1. 启动项目

npm run start

store目录结构

三 Redux实现counter计数器

1. RTK创建counterSotre

src/store/modules/counterStore.js

js 复制代码
import { createSlice } from "@reduxjs/toolkit";

const counterStore = createSlice({
    name: 'counter',
    // 初始化state
    initialState: {
        count: 0,
    },
    // 修改状态的方法 (同步), 支持直接修改state
    reducers: {
        increment: (state) => {
            state.count++;
        },
        decrement: (state) => {
            state.count--;
        },
    },
})

// 解构并导出actionCreater函数, 用于后续组件中使用
export const { increment, decrement } = counterStore.actions;
// 默认导出reducer
export default counterStore.reducer;

2. 创建store,引入子模块

src/store/index.js

js 复制代码
import { configureStore } from "@reduxjs/toolkit";
// 导入子模块 counterStore
import counterStore from "./modules/counterStore";

const store = configureStore({
    reducer: {
        counter: counterStore,
    }
})  

export default store;

3. 为React注入store

  • 使用react-redux连接Redux和React
  • 内置的Provider组件, 通过store参数将创建好的store实例注入到React中
js 复制代码
import React from 'react';
import ReactDOM from 'react-dom/client';

// 导入Provider组件
import { Provider } from 'react-redux';
// 导入store实例
import store from './store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
        {/* 使用Provider */}
        <Provider store={store}>
            <App />
        </Provider>
  </React.StrictMode>
);

4. React组件中使用/修改store

4.1 使用store

  • 使用store的数据, 需要用到钩子函数 useSelector() , 他的作用就是把store的数据映射到组件中
jsx 复制代码
// 导入 useSelector 钩子
import { useSelector } from "react-redux"

function App() {
    // 使用store的数据, 需要用到 useSelector 这个钩子函数, 他的作用就是把store的数据映射到组件中
    const { count } = useSelector((state) => state.counter)

    return (
        <div className="App">
            <button>-</button>
            <span>{ count }</span>
            <button>+</button>
        </div>
    )
}

export default App

4.2 修改store

  • 修改store的数据, 需要借助到 钩子函数useDispatch, 他的作用是生成提交action对象的dispatch的函数
jsx 复制代码
// 导入 useDispatch 钩子
import { useSelector, useDispatch } from "react-redux"
// 导入 increment, decrement 加减的逻辑函数
import { increment, decrement } from './store/modules/counterStore';
function App() {
    // 使用store的数据, 需要用到 useSelector 这个钩子函数, 他的作用就是把store的数据映射到组件中
    const { count } = useSelector((state) => state.counter)
    // 修改store的数据, 需要借助到 useDispatch(), 他的作用是生成提交action对象的dispatch的函数
    const dispatch = useDispatch();
    return (
        <div className="App">
            <button onClick={ () => dispatch(decrement()) }>-</button>
            <span>{ count }</span>
            <button onClick={ () => dispatch(increment()) }>+</button>
        </div>
    )
}

export default App

5. 提交action传参

  • 在reducers的同步修改方法中, 添加action对象参数, 在调用actionCreater时传递参数,参数就会被传到action对象的payload属性

App.js

jsx 复制代码
// 导入 useDispatch 钩子
import { useSelector, useDispatch } from "react-redux"
// 导入 increment, decrement 加减的逻辑函数
import { addNum } from './store/modules/counterStore';
function App() {
    // 使用store的数据, 需要用到 useSelector 这个钩子函数, 他的作用就是把store的数据映射到组件中
    const { count } = useSelector((state) => state.counter)
    // 修改store的数据, 需要借助到 useDispatch(), 他的作用是生成提交action对象的dispatch的函数
    const dispatch = useDispatch();
    return (
        <div className="App">
            <span>{ count }</span>
            <button onClick={ () => dispatch(addNum(10))}>+10</button>
            <button onClick={ () => dispatch(addNum(20))}>+20</button>
        </div>
    )
}

export default App

counterStore.js

js 复制代码
import { createSlice } from "@reduxjs/toolkit";

const counterStore = createSlice({
    name: 'counter',
    // 初始化state
    initialState: {
        count: 0,
    },
    // 修改状态的方法 (同步), 支持直接修改state
    reducers: {
        increment: (state) => {
            state.count++;
        },
        decrement: (state) => {
            state.count--;
        },
        // 传递参数的action
        addNum: (state, action) =>  { 
            state.count += action.payload;
        },
    },
})

// 解构并导出actionCreater函数, 用于后续组件中使用
export const { increment, decrement, addNum } = counterStore.actions;
// 默认导出reducer
export default counterStore.reducer;

四 Redux - 异步状态操作

  1. 创建一个新的store
  2. 单独封装一个函数,在函数内部return一个新函数
  3. 新函数中,封装异步请求获取数据, 使用dispatch提交, 调用同步action,传入请求回来的数据
  4. 组件中dispatch写法保持不变

/src/store/modules/channelStore.js

js 复制代码
// 没有axios, 要先安装一下  npm i axios

import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
// 创建一个channel的store
const channelStore = createSlice({
    name: 'channel',
    initialState: {
        channelList: [],
    },
    reducers: {
        setChannel: (state, action) => { 
            state.channelList = action.payload;
        }
    },
})

const { setChannel } = channelStore.actions;
// 封装异步请求, 获取数据
export const getChannelList = () => { 
    return async (dispatch) => { 
        const res = await axios.get('http://geek.itheima.net/v1_0/channels')
        // 调用同步的action,传入请求回来的数据,并生成一个acion对象, 使用dispatch提交
        dispatch(setChannel(res.data.data.channels))
    }
}


// 默认导出reducer
export default channelStore.reducer;

/src/store/index.js

js 复制代码
import channelStore from './modules/channelStore'
const store = configureStore({
    reducer: {
        channel: channelStore,
    }
})  

export default store;

App.js

jsx 复制代码
import { useSelector, useDispatch } from "react-redux"
import { useEffect } from "react";
import { getChannelList } from './store/modules/channelStore'
function App() {
    const { channelList } = useSelector(state => state.channel)
    const dispatch = useDispatch();
    // 调用请求, 获取数据
    useEffect(() => { 
        // 严格模式下, 会触发两次
        dispatch(getChannelList())
    }, [dispatch])
    return (
        <div className="App">
            <ul>
                {
                    channelList.map(item => <li key={ item.id }>{ item.name }</li>)
                }
            </ul>
        </div>
    )
}

export default App
相关推荐
学渣y38 分钟前
React状态管理-对state进行保留和重置
javascript·react.js·ecmascript
_龙衣1 小时前
将 swagger 接口导入 apifox 查看及调试
前端·javascript·css·vue.js·css3
进取星辰2 小时前
25、Tailwind:魔法速记术——React 19 样式新思路
前端·react.js·前端框架
x-cmd3 小时前
[250512] Node.js 24 发布:ClangCL 构建,升级 V8 引擎、集成 npm 11
前端·javascript·windows·npm·node.js
夏之小星星3 小时前
el-tree结合checkbox实现数据回显
前端·javascript·vue.js
crazyme_63 小时前
前端自学入门:HTML 基础详解与学习路线指引
前端·学习·html
撸猫7913 小时前
HttpSession 的运行原理
前端·后端·cookie·httpsession
亦世凡华、3 小时前
Rollup入门与进阶:为现代Web应用构建超小的打包文件
前端·经验分享·rollup·配置项目·前端分享
Bl_a_ck4 小时前
【React】Craco 简介
开发语言·前端·react.js·typescript·前端框架
augenstern4165 小时前
webpack重构优化
前端·webpack·重构