Skip to content

Redux 状态管理

在大型项目中使用 Redux 管理全局状态(以 Todo List 为例),可以帮助你实现 可预测、可调试和可维护 的状态管理,特别是在多人协作或复杂交互的场景中。以下是一个结构化的讲解,适合用于大型项目:


🧩 一、项目结构建议(大型项目)

bash
src/
├── app/
   └── store.ts              # Redux store 配置
├── features/
   └── todos/
       ├── todosSlice.ts     # todos 状态逻辑(reducer + actions)
       ├── todosAPI.ts       # 处理异步操作,如fetchTodos
       └── components/       # UI 组件
├── hooks/
   └── useAppDispatch.ts     # 自定义 dispatch hook
├── types/
   └── todo.ts               # Todo 类型定义
└── index.tsx

📦 二、初始化 Redux Store

ts
// src/app/store.ts
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'

export const store = configureStore({
  reducer: {
    todos: todosReducer,
  },
})

// 为组件提供类型支持
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

🧠 三、定义状态 Slice(reducer + actions)

ts
// src/features/todos/todosSlice.ts
import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'
import { Todo } from '../../types/todo'
import { fetchTodosFromAPI } from './todosAPI'

interface TodosState {
  items: Todo[]
  loading: boolean
  error: string | null
}

const initialState: TodosState = {
  items: [],
  loading: false,
  error: null,
}

// 异步 action 示例
export const fetchTodos = createAsyncThunk('todos/fetchTodos', async () => {
  return await fetchTodosFromAPI()
})

const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    addTodo(state, action: PayloadAction<Todo>) {
      state.items.push(action.payload)
    },
    toggleTodo(state, action: PayloadAction<number>) {
      const todo = state.items.find(t => t.id === action.payload)
      if (todo) {
        todo.completed = !todo.completed
      }
    },
    deleteTodo(state, action: PayloadAction<number>) {
      state.items = state.items.filter(t => t.id !== action.payload)
    },
  },
  extraReducers: builder => {
    builder
      .addCase(fetchTodos.pending, state => {
        state.loading = true
        state.error = null
      })
      .addCase(fetchTodos.fulfilled, (state, action) => {
        state.loading = false
        state.items = action.payload
      })
      .addCase(fetchTodos.rejected, (state, action) => {
        state.loading = false
        state.error = action.error.message || 'Error fetching todos'
      })
  },
})

export const { addTodo, toggleTodo, deleteTodo } = todosSlice.actions
export default todosSlice.reducer

🧑‍💻 四、定义类型(可复用)

ts
// src/types/todo.ts
export interface Todo {
  id: number
  text: string
  completed: boolean
}

🔄 五、调用 Redux:React 中使用状态

tsx
// src/features/todos/components/TodoList.tsx
import { useSelector, useDispatch } from 'react-redux'
import { RootState } from '../../../app/store'
import { toggleTodo, deleteTodo } from '../todosSlice'

export default function TodoList() {
  const todos = useSelector((state: RootState) => state.todos.items)
  const dispatch = useDispatch()

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>
          <span
            style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
            onClick={() => dispatch(toggleTodo(todo.id))}
          >
            {todo.text}
          </span>
          <button onClick={() => dispatch(deleteTodo(todo.id))}>Delete</button>
        </li>
      ))}
    </ul>
  )
}

🔄 六、异步操作(fetch 远程 todos)

tsx
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchTodos } from '../todosSlice'
import { RootState } from '../../../app/store'

export function TodoFetcher() {
  const dispatch = useDispatch()
  const loading = useSelector((state: RootState) => state.todos.loading)

  useEffect(() => {
    dispatch(fetchTodos())
  }, [dispatch])

  return loading ? <div>Loading...</div> : null
}

✅ 七、总结:大型项目中使用 Redux 的关键点

项目实践点描述
模块化 Slice每个领域(todos、users、auth)都使用独立 slice 管理
使用 createAsyncThunk管理异步数据请求,并自动处理 loading/error 状态
类型安全配合 TypeScript 定义 RootStateTodo 类型,减少出错
统一 hooks自定义 useAppDispatch / useAppSelector 简化使用
代码分层slice.ts 处理状态,API.ts 管理请求,组件只负责 UI