redux 简单入门

发布时间 2023-10-29 01:06:45作者: zjy4fun

redux 是一个状态管理库,独立存在,可以借助 react-redux 库与 react 配合使用。

介绍几个概念:

  • store 包含状态数据,所有组件可以访问并操作里面的状态数据
  • action 描述了发生了什么动作和事情,不包含状态本身
  • reducer 纯函数,接受当前状态和一个动作作为参数,并返回一个新的状态
  • dispatch 用于把动作(action)发送给 仓库(store),触发状态的变化
  • subscribe 订阅状态变化,以便在状态发生改变的时候执行特定的逻辑,触发 UI 发生变化

下面是一个使用 redux 实现 counter 的简单示例

<html>
  <button id="decrement">-</button>
  <span id="count">0</span>
  <button id="increment">+</button>

  <script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<!-- 
  state 一个对象,存放着我们管理的数据状态
  action 一个对象,用来描述你想怎么修改数据
  reducer 一个函数,更具 action 的描述生成一个新的 state
 -->
  <script>
    // 1. 定义 reducer 函数:作用是根据不同的 action 对象,返回不同的新的 state
    // state: 管理的数据初始状态
    // action: 对象 type 标记当前想要做什么样的修改
    function reducer(state = { count: 0 }, action) {
      // 数据不可变:基于原始状态生成一个新的状态
      if(action.type === 'INCREMENT') {
        return { count: state.count + 1}
      }
      if(action.type === 'DECREMENT') {
        return { count: state.count - 1}
      }
      return state
    }
    // 2. 使用 reducer 函数创建 store 实例
    const store = Redux.createStore(reducer)
    // 3. 通过 store 实例的 subscribe 订阅数据变化
    // 回调函数可以在每次 state 发生变化的时候自动执行
    store.subscribe(() => {
        console.log('state 发生变化了', store.getState())
        // 5. 通过 store 实例的 getState 方法获取最新状态更新到视图中
        document.getElementById('count').innerText = store.getState().count
    })
    // 4. 通过 store 实例的 dispatch 函数触发 action 更改状态
    const inBtn = document.getElementById('increment')
    inBtn.addEventListener('click', () => {
      store.dispatch({ type: 'INCREMENT' })
    })
    
    const dBtn = document.getElementById('decrement')
    dBtn.addEventListener('click', () => {
      store.dispatch({ type: 'DECREMENT' })
    })
  </script>
</html>

 

单独使用 redux 很复杂,官方推荐使用 @reduxjs/toolkit 简化 redux 的使用

  • createSlice 一个用于创建 Redux Reducer 和 Action Creator 的函数,自动生成 Reducer 函数和相应的动作创建函数,大大减少了手动编写 Reducer 和动作创建函数的工作量。
  • configureStore  封装了创建 Redux 仓库的过程

使用 react-redux 将 redux 注入到 react 中

  • Provider 将 store 注入到 react 中,一般包裹在顶层,以便内部的组件都能访问
  • useSelector 用于从 redux 中取对应的数据

store 目录

➜  store git:(main) tree .
.
├── index.js
└── modules
    ├── channelStore.js
    └── counterStore.js

counterStore.js

import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({
  name: 'counter',
  initialState: {
    count: 0
  },
  reducers: {
    increment: (state) => {
      state.count += 1
    },
    decrement: (state) => {
      state.count -= 1
    },
    addToNum: (state, action) => {
      state.count = action.payload
    }
  }
})

// 按需导出 actionCreator
export const { increment, decrement, addToNum } = counterStore.actions
export default counterStore.reducer

store/index.js 对各个模块的 store 做整合

import { configureStore } from "@reduxjs/toolkit"
import counterReducer from './modules/counterStore'
import channelStore from "./modules/channelStore"


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

export default store

顶层组件将 redux 注入到 react 程序

<Provider store={store}>
    <App />
</Provider>

使用 useSelector 取数据

const { count } = useSelector(state => state.counter)

使用 dispatch 触发 action

<button onClick={() => dispatch(decrement())}>-</button>

 

完整代码可以参考项目  https://github.com/zjy4fun/notes/tree/main/frontend/react/redux/react-redux-pro