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
相关推荐
_AaronWong20 分钟前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
cxxcode21 分钟前
I/O 多路复用:从浏览器到 Linux 内核
前端
用户54330814419429 分钟前
AI 时代,前端逆向的门槛已经低到离谱 — 以 Upwork 为例
前端
JarvanMo33 分钟前
Flutter 版本的 material_ui 已经上架 pub.dev 啦!快来抢先体验吧。
前端
恋猫de小郭1 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程
哀木1 小时前
给自己整一个 claude code,解锁编程新姿势
前端
程序员鱼皮1 小时前
GitHub 关注突破 2w,我总结了 10 个涨星涨粉技巧!
前端·后端·github
UrbanJazzerati1 小时前
Vue3 父子组件通信完全指南
前端·面试
是一碗螺丝粉1 小时前
5分钟上手LangChain.js:用DeepSeek给你的App加上AI能力
前端·人工智能·langchain
wuhen_n1 小时前
双端 Diff 算法详解
前端·javascript·vue.js