Redux的简介及其在React中的应用

Redux

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

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

使用步骤:

  1. 定义一个 reducer 函数 (根据当前想要做的修改返回一个新的状态);

  2. 使用createStore方法传入 reducer函数 生成一个store实例对象;

  3. 使用store实例的 subscribe方法 订阅数据的变化(数据一旦变化,可以得到通知);

  4. 使用store实例的 dispatch方法提交action对象触发数据变化(告诉reducer你想怎么改数据);

  5. 使用store实例的 getState方法 获取最新的状态数据更新到视图中。

管理数据流程:

为了职责清晰,数据流向明确,Redux把整个数据修改的流程分成了三个核心概念,分别是:state、action和reducer

  1. state:一个对象 存放着我们管理的数据状态;

  2. action:一个对象 用来描述你想怎么改数据;

  3. reducer:一个函数 根据action的描述生成一个新的state。

Redux与React环境准备

配套工具

在React中使用redux,官方要求安装俩个其他插件 - Redux Toolkit 和 react-redux

  1. Redux Toolkit(RTK)- 官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式

  2. react-redux - 用来 链接 Redux 和 React组件 的中间件。

配置基础环境

  1. 使用 CRA 快速创建 React 项目

    复制代码
    npx create-react-app react-redux
  2. 安装配套工具

    复制代码
    npm i @reduxjs/toolkit react-redux
  3. 启动项目

    复制代码
    npm run start

store目录结构设计

  1. 通常集中状态管理的部分都会单独创建一个单独的 store 目录

  2. 应用通常会有很多个子store模块,所以创建一个 modules 目录,在内部编写业务分类的子store

  3. store中的入口文件 index.js 的作用是组合modules中所有的子模块,并导出store

Redux与React 实现counter

使用React Toolkit 创建counterStore
javascript 复制代码
// src => store => modules => counterStore.js
import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({
  name: 'counter',//模块的名称
  // 初始化state
  initialState: {
    count: 0
  },
  // 修改数据的方法,都是同步方法,支持直接修改
  reducers: {
    incremnent(state) {
      state.count++
    },
    decrement(state) {
      state.count--
    }
  }
})

// 解构出来actionCreater函数
const { incremnent, decrement } = counterStore.actions
// 获取reducer
const reducer = counterStore.reducer

// 以按需导出的方式导出actionCreater
export { incremnent, decrement }
// 以默认导出的方式导出reducer
export default reducer
javascript 复制代码
// src => store => index.js
import { configureStore } from "@reduxjs/toolkit";
// 导入子模块reducer
import counterReducer from "./modules/counterStore";

const store = configureStore({
  reducer: {
    counter: counterReducer
  }
})

export default store
为React注入store

react-redux负责把Redux和React 链接 起来,内置 Provider组件 通过 store 参数把创建好的store实例注入到应用中,链接正式建立。

javascript 复制代码
// src => index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './store';
import { Provider } from 'react-redux';

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

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
React组件使用store中的数据

在React组件中使用store中的数据,需要用到一个 钩子函数 - useSelector,它的作用是把store中的数据映射到组件中,使用样例如下:

javascript 复制代码
import { useSelector } from 'react-redux'
function App() {
  const { count } = useSelector(state => state.counter)
  return (
    <div className="App">
      {count}
    </div>
  );
}
export default App;
React组件修改store中的数据

React组件中修改store中的数据需要借助另外一个hook函数 - useDispatch,它的作用是生成提交action对象的dispatch函数,使用样例如下:

javascript 复制代码
import { useSelector, useDispatch } from 'react-redux'
// 导入actionCreater
import { incremnent, decrement } from './store/modules/counterStore'
function App() {
  const { count } = useSelector(state => state.counter)
  const dispathc = useDispatch()
  return (
    <div className="App">
      <button onClick={() => dispathc(decrement())}>-</button>
      {count}
      <button onClick={() => dispathc(incremnent())}>+</button>
    </div>
  );
}
export default App;
Redux与React 提交action传参
  • 需求说明:

    组件中有俩个按钮 add to 10add to 20 可以直接把count值修改到对应的数字,目标count值是在组件中传递过去的,需要在提交action的时候传递参数

  • 提交action传参实现需求:

    • 在reducers的同步修改方法中添加action对象参数

    • 调用actionCreater的时候传递参数 ,参数会被传递到action对象payload属性上。

javascript 复制代码
// src => app.js
import { useSelector, useDispatch } from 'react-redux'
// 导入actionCreater
import { incremnent, decrement, addToNum } from './store/modules/counterStore'
function App() {
  const { count } = useSelector(state => state.counter)
  const dispathc = useDispatch()
  return (
    <div className="App">
      <button onClick={() => dispathc(decrement(10))}>-</button>
      {count}
      <button onClick={() => dispathc(incremnent(10))}>+</button>
      <button onClick={() => dispathc(addToNum(10))}>add to 10</button>
      <button onClick={() => dispathc(addToNum(20))}>add to 20</button>
    </div>
  );
}
export default App;
javascript 复制代码
// src => store => counterStore.js
import { createSlice } from '@reduxjs/toolkit'
const counterStore = createSlice({
  name: 'counter',//模块的名称
  // 初始化state
  initialState: {
    count: 0
  },
  // 修改数据的方法,都是同步方法,支持直接修改
  reducers: {
    incremnent(state) {
      state.count++
    },
    decrement(state) {
      state.count--
    },
    addToNum(state, actions) {
      state.count = actions.payload
    }
  }
})
// 解构出来actionCreater函数
const { incremnent, decrement, addToNum } = counterStore.actions
// 获取reducer
const reducer = counterStore.reducer
// 以按需导出的方式导出actionCreater
export { incremnent, decrement, addToNum }
// 以默认导出的方式导出reducer
export default reducer
Redux与React 异步状态操作

异步操作步骤:

  1. 创建store的写法保持不变,配置好同步修改状态的方法;

  2. 单独封装一个函数,在函数内部return一个新函数,在新函数中;

    2.1 封装异步请求获取数据;

    2.2 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交。

  3. 组件中dispatch的写法保持不变。

javascript 复制代码
import { useSelector, useDispatch } from 'react-redux'
// 导入actionCreater
import { incremnent, decrement, addToNum } from './store/modules/counterStore'
import { useEffect } from 'react'
import { fetchChannelList } from './store/modules/channelStore'
function App() {
  const { count } = useSelector(state => state.counter)
  const { channelList } = useSelector(state => state.channel)
  const dispathc = useDispatch()
  // 使用useEffect触发异步请求执行
  useEffect(() => {
    dispathc(fetchChannelList())
  }, [])
  return (
    <div className="App">
      <button onClick={() => dispathc(decrement(10))}>-</button>
      {count}
      <button onClick={() => dispathc(incremnent(10))}>+</button>
      <button onClick={() => dispathc(addToNum(10))}>add to 10</button>
      <button onClick={() => dispathc(addToNum(20))}>add to 20</button>

      <ul>
        {channelList.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}
export default App;
javascript 复制代码
// src => store => modules => channelStore
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
const channelStore = createSlice({
  name: 'channel',
  initialState: {
    channelList: []
  },
  reducers: {
    setChannels(state, actions) {
      state.channelList = actions.payload
    }
  }
})
// 异步请求部分
const { setChannels } = channelStore.actions
const fetchChannelList = () => {
  return async (dispathc) => {
    const res = await axios.get('http://geek.itheima.net/v1_0/channels')
    dispathc(setChannels(res.data.data.channels))
  }
}
export { fetchChannelList }
const reducer = channelStore.reducer
export default reducer
相关推荐
万少14 分钟前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL20 分钟前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl0235 分钟前
java web5(黑马)
java·开发语言·前端
Amy.Wang37 分钟前
前端如何实现电子签名
前端·javascript·html5
海天胜景39 分钟前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼40 分钟前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿41 分钟前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再44 分钟前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5551 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架
拾光拾趣录1 小时前
CSS 深入解析:提升网页样式技巧与常见问题解决方案
前端·css