Yuan的博客
EN

Redux

Redux 基础

Redux 是 JavaScript 应用的可预测状态容器。它帮助您编写行为一致、可在不同环境中运行且易于测试的应用程序。

核心概念

  1. Store:保存应用状态的唯一数据源
  2. Actions:描述发生了什么的普通对象
  3. Reducers:指定状态如何响应 actions 而变化的纯函数
  4. Dispatch:触发状态变化的唯一方式

三大原则

  1. 单一数据源:全局状态存储在单一 store 中
  2. 状态只读:改变状态的唯一方式是触发 action
  3. 使用纯函数进行更改:Reducers 是接收先前状态和 action 并返回新状态的纯函数

设置 Redux

安装

npm install redux react-redux @reduxjs/toolkit

基本 Store 设置

import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'

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

Actions 和 Action Creators

Actions 是将数据从应用发送到 store 的信息载荷。

// Action types
const INCREMENT = 'INCREMENT'
const DECREMENT = 'DECREMENT'

// Action creators
const increment = () => ({
  type: INCREMENT,
})

const decrement = () => ({
  type: DECREMENT,
})

const incrementByAmount = (amount) => ({
  type: 'INCREMENT_BY_AMOUNT',
  payload: amount,
})

Reducers

Reducers 指定应用状态如何响应 actions 而变化。

const initialState = {
  value: 0,
}

function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return {
        ...state,
        value: state.value + 1,
      }
    case 'DECREMENT':
      return {
        ...state,
        value: state.value - 1,
      }
    case 'INCREMENT_BY_AMOUNT':
      return {
        ...state,
        value: state.value + action.payload,
      }
    default:
      return state
  }
}

Redux Toolkit (RTK)

Redux Toolkit 是官方的、开箱即用的高效 Redux 开发工具集。

创建 Slice

import { createSlice } from '@reduxjs/toolkit'

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

export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer

连接 React 组件

使用 React-Redux Hooks

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement, incrementByAmount } from './counterSlice'

function Counter() {
  const count = useSelector((state) => state.counter.value)
  const dispatch = useDispatch()

  return (
    <div>
      <button onClick={() => dispatch(increment())}>+</button>
      <span>{count}</span>
      <button onClick={() => dispatch(decrement())}>-</button>
      <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
    </div>
  )
}

Provider 设置

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { store } from './store'
import App from './App'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

使用 Redux Thunk 处理异步操作

Thunk Action Creator

import { createAsyncThunk } from '@reduxjs/toolkit'

export const fetchUserById = createAsyncThunk('users/fetchById', async (userId) => {
  const response = await fetch(`/api/users/${userId}`)
  return response.json()
})

在 Slice 中处理异步 Actions

const usersSlice = createSlice({
  name: 'users',
  initialState: {
    entities: [],
    loading: 'idle',
  },
  reducers: {
    // standard reducer logic
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUserById.pending, (state) => {
        state.loading = 'pending'
      })
      .addCase(fetchUserById.fulfilled, (state, action) => {
        state.loading = 'idle'
        state.entities.push(action.payload)
      })
      .addCase(fetchUserById.rejected, (state) => {
        state.loading = 'idle'
      })
  },
})

最佳实践

  1. 使用 Redux Toolkit:减少样板代码并包含实用工具
  2. 规范化状态结构:像数据库一样组织状态
  3. 保持状态最小化:仅将真正全局的数据放入 Redux
  4. 使用选择器:创建可复用的函数从状态中提取数据
  5. 拆分 Reducers:使用 combineReducers 管理状态的不同部分

何时使用 Redux

Redux 在以下情况最有用:

  • 应用有大量状态
  • 状态频繁更新
  • 更新状态的逻辑可能复杂
  • 应用有中等或大型代码库
  • 多个开发人员在应用上工作

常见模式

选择器函数

// 选择器
const selectCounter = (state) => state.counter.value
const selectCounterByAmount = (state, amount) => state.counter.value * amount

中间件

const loggerMiddleware = (store) => (next) => (action) => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

Redux 提供了一种可预测的方式来管理复杂应用中的状态,使调试更容易并启用强大的开发工具。