<返回目录     Powered by claud/xia兄

第12课: 状态管理

Redux、Context API、状态管理最佳实践

课程内容

本课程将详细介绍React应用中的状态管理相关知识和实践技巧,包括React内置的状态管理方案、Redux的基本使用、Redux Toolkit的最佳实践等核心概念。

核心概念

1. 状态管理基础

2. React内置状态管理

2.1 useState Hook

// useState基本使用
import React, { useState } from 'react';

function Counter() {
  // 声明一个名为count的状态变量,初始值为0
  const [count, setCount] = useState(0);
  
  // 声明多个状态变量
  const [name, setName] = useState('React');
  const [isVisible, setIsVisible] = useState(true);
  
  return (
    

计数器: {count}

名称: {name}

setName(e.target.value)} />

可见性: {isVisible ? '可见' : '隐藏'}

); } export default Counter;

2.2 useReducer Hook

// useReducer基本使用
import React, { useReducer } from 'react';

// 定义初始状态
const initialState = {
  count: 0,
  step: 1
};

// 定义reducer函数
function counterReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + state.step };
    case 'decrement':
      return { ...state, count: state.count - state.step };
    case 'reset':
      return { ...state, count: 0 };
    case 'setStep':
      return { ...state, step: action.payload };
    default:
      return state;
  }
}

function CounterWithReducer() {
  // 使用useReducer
  const [state, dispatch] = useReducer(counterReducer, initialState);
  
  return (
    

计数器: {state.count}

步长: {state.step}

dispatch({ type: 'setStep', payload: parseInt(e.target.value) || 1 })} />
); } export default CounterWithReducer;

2.3 Context API

// Context API基本使用
import React, { createContext, useContext, useState } from 'react';

// 创建Context
const ThemeContext = createContext();

// 创建Provider组件
export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
  };
  
  const value = {
    theme,
    toggleTheme
  };
  
  return (
    
      {children}
    
  );
}

// 创建自定义Hook
export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
}

// 使用Context的组件
function ThemedButton() {
  const { theme, toggleTheme } = useTheme();
  
  return (
    
  );
}

// 应用根组件
function App() {
  return (
    
      

Context API示例

); } export default App;

3. Redux基本使用

3.1 Redux核心概念

3.2 Redux基本配置

// Redux基本配置
// 1. 安装Redux和React-Redux
// npm install redux react-redux

// 2. 创建action types
const INCREMENT = 'counter/increment';
const DECREMENT = 'counter/decrement';
const RESET = 'counter/reset';
const SET_STEP = 'counter/setStep';

// 3. 创建action creators
export const increment = () => ({
  type: INCREMENT
});

export const decrement = () => ({
  type: DECREMENT
});

export const reset = () => ({
  type: RESET
});

export const setStep = (step) => ({
  type: SET_STEP,
  payload: step
});

// 4. 创建reducer
const initialState = {
  count: 0,
  step: 1
};

export function counterReducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      return {
        ...state,
        count: state.count + state.step
      };
    case DECREMENT:
      return {
        ...state,
        count: state.count - state.step
      };
    case RESET:
      return {
        ...state,
        count: 0
      };
    case SET_STEP:
      return {
        ...state,
        step: action.payload
      };
    default:
      return state;
  }
}

// 5. 创建store
import { createStore } from 'redux';
import { counterReducer } from './reducers';

export const store = createStore(counterReducer);

// 6. 在React应用中使用Redux
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  
    
      
    
  
);

// 7. 在组件中使用Redux
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, reset, setStep } from './actions';

function Counter() {
  // 从store中获取状态
  const { count, step } = useSelector(state => state);
  
  // 获取dispatch方法
  const dispatch = useDispatch();
  
  return (
    

Redux计数器: {count}

步长: {step}

dispatch(setStep(parseInt(e.target.value) || 1))} />
); } export default Counter;

4. Redux Toolkit

4.1 Redux Toolkit简介

Redux Toolkit是官方推荐的Redux开发工具集,它简化了Redux的使用,减少了样板代码。

4.2 Redux Toolkit基本使用

// Redux Toolkit基本使用
// 1. 安装Redux Toolkit和React-Redux
// npm install @reduxjs/toolkit react-redux

// 2. 创建slice
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0,
    step: 1
  },
  reducers: {
    increment: (state) => {
      // Redux Toolkit允许我们在reducers中直接修改状态
      state.count += state.step;
    },
    decrement: (state) => {
      state.count -= state.step;
    },
    reset: (state) => {
      state.count = 0;
    },
    setStep: (state, action) => {
      state.step = action.payload;
    }
  }
});

// 导出action creators
export const { increment, decrement, reset, setStep } = counterSlice.actions;

// 导出reducer
export default counterSlice.reducer;

// 3. 配置store
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './features/counter/counterSlice';
import todoReducer from './features/todo/todoSlice';

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

// 4. 在组件中使用
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, reset, setStep } from './features/counter/counterSlice';

function Counter() {
  const { count, step } = useSelector(state => state.counter);
  const dispatch = useDispatch();
  
  return (
    

Redux Toolkit计数器: {count}

步长: {step}

dispatch(setStep(parseInt(e.target.value) || 1))} />
); } export default Counter;

5. 异步状态管理

5.1 使用Redux Toolkit的createAsyncThunk

// 异步状态管理
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { fetchTodos } from '../services/api';

// 创建异步thunk
export const getTodos = createAsyncThunk(
  'todo/fetchTodos',
  async (_, { rejectWithValue }) => {
    try {
      const response = await fetchTodos();
      return response;
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);

// 创建todo slice
const todoSlice = createSlice({
  name: 'todo',
  initialState: {
    items: [],
    status: 'idle', // idle, loading, succeeded, failed
    error: null
  },
  reducers: {
    addTodo: (state, action) => {
      state.items.push(action.payload);
    },
    removeTodo: (state, action) => {
      state.items = state.items.filter(todo => todo.id !== action.payload);
    },
    updateTodo: (state, action) => {
      const index = state.items.findIndex(todo => todo.id === action.payload.id);
      if (index !== -1) {
        state.items[index] = action.payload;
      }
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(getTodos.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(getTodos.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.items = action.payload;
      })
      .addCase(getTodos.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.payload;
      });
  }
});

export const { addTodo, removeTodo, updateTodo } = todoSlice.actions;
export default todoSlice.reducer;

// 在组件中使用
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getTodos, addTodo, removeTodo } from './features/todo/todoSlice';

function TodoList() {
  const { items, status, error } = useSelector(state => state.todo);
  const dispatch = useDispatch();
  
  useEffect(() => {
    if (status === 'idle') {
      dispatch(getTodos());
    }
  }, [status, dispatch]);
  
  const handleAddTodo = () => {
    const newTodo = {
      id: Date.now(),
      text: `Todo ${items.length + 1}`,
      completed: false
    };
    dispatch(addTodo(newTodo));
  };
  
  return (
    

Todo列表

{status === 'loading' &&
加载中...
} {status === 'failed' &&
错误: {error}
}
    {items.map(todo => (
  • {todo.text}
  • ))}
); } export default TodoList;

6. 状态管理最佳实践

6.1 状态管理的设计原则

6.2 性能优化

6.3 状态管理的选择

状态管理方案 适用场景 优点 缺点
useState 组件内部简单状态 简单易用,内置Hook 不适合复杂状态和跨组件共享
useReducer 组件内部复杂状态 适合复杂状态逻辑,可预测性强 需要编写更多代码
Context API 跨组件简单状态共享 内置API,无需额外依赖 可能导致不必要的重渲染
Redux 大型应用全局状态管理 可预测性强,工具生态丰富 样板代码多,学习曲线陡
Redux Toolkit 大型应用全局状态管理 简化Redux使用,减少样板代码 仍有一定学习曲线

7. 其他状态管理库

最佳实践:
注意事项:

实践练习

练习任务:
  1. 基础练习:

    使用useState和useReducer实现一个计数器应用,包含以下功能:

    • 增加、减少、重置功能
    • 可调整步长
    • 显示当前计数和步长
  2. 中级练习:

    使用Context API实现一个主题切换功能,包含以下功能:

    • 浅色/深色主题切换
    • 多个组件共享主题状态
    • 主题状态持久化(localStorage)
  3. 高级练习:

    使用Redux Toolkit实现一个待办事项应用,包含以下功能:

    • 获取待办事项列表
    • 添加、删除、更新待办事项
    • 标记待办事项为完成/未完成
    • 过滤待办事项(全部、完成、未完成)
    • 异步操作状态管理
  4. 综合练习:

    构建一个完整的React应用,使用适当的状态管理方案:

    • 用户认证状态管理
    • 数据获取和缓存
    • UI状态管理
    • 性能优化

总结

通过本课程学习,你应该掌握了React状态管理的核心知识和实践技巧:

状态管理是React应用开发中的重要组成部分,合理的状态管理方案可以提高应用的可维护性和性能。继续深入学习和实践,你将能够构建更加复杂和功能完善的React应用。