🚀 React 状态管理全解:从 Redux 到 Redux Toolkit 实战教程

1 阅读4分钟

作为一名前端开发人员,你或许对 React 的组件状态管理游刃有余,但当项目变得越来越复杂,组件间通信开始变得混乱时,一个健壮的全局状态管理工具显得尤为重要。这时候,Redux 和它的亲兄弟 react-redux、@reduxjs/toolkit 就派上了用场。

本文将带你从 Redux 的基本概念入门,一步步理解如何借助 react-redux@reduxjs/toolkit 更高效、优雅地管理状态,最终构建现代、可维护的 React 应用。


🧩 一、Redux 是什么?

Redux 是一个可预测状态容器,最初为 JavaScript 应用而设计。它有以下几个核心概念:

  • Store:整个应用的状态存储在一个对象树中。
  • Action:一个描述“发生了什么”的普通对象。
  • Reducer:一个纯函数,接收旧的 state 和 action,返回新的 state。
  • Dispatch:触发 action,通知 reducer 更新 state。

Redux 的核心思想是:状态是只读的,只有通过 dispatch 一个 action 才能改变它,且修改逻辑由 reducer 函数集中管理。

Redux 由几个关键组件组成,它们协同工作以管理应用程序状态:

image.png

🔧 简单 Redux 使用示例

// store/actions/index.js
export const addNum = () => {
  return {
    type: 'ADD_NUM',
  }
}

export const subNum = () => {
  return {
    type: 'SUB_NUM',
  }
}
export const setNum = num => {
  return {
    type: 'SET_NUM',
    data:num
  }
}
// store/reducer/index.js
const defaultState = {
  count: 0
}

function reducer (state = defaultState,action) {
  console.log(action,'action')
  console.log(defaultState,'defaultState')
  switch (action.type) {
    case 'ADD_NUM':
      return {
        ...state,
        count: state.count + 1
      }
    case 'SUB_NUM' :
      return {
        ...state,
        count: state.count - 1
      }
    case 'SET_NUM':
      return {
        ...state,
        count: action.data
      }
    default:
      return state
  }
}

export default reducer
// store/index.js
import { createStore } from 'redux'
import reducer from './reducer/index.js'
const store = createStore(reducer)

export default store
import { addNum, subNum, setNum} from './store/actions/index.js'
function App (props) {
  const { getState,dispatch, } = props.store
  const { count } = getState()
  const add = ()=> {
    dispatch(addNum())
  }

  const sub = ()=> {
    dispatch(subNum())
  }

  const set = (num)=> {
    dispatch(setNum(num))
  }
  return (
    <div id='root'>
      <div>
        <span>计数器:{count}</span>
        <button onClick={add}>加1</button>
        <button onClick={sub}>减1</button>
        <button onClick={()=> set(100)}>100</button>
        <button onClick={()=> set(200)}>200</button>
      </div>
    </div >
  );
}

export default App;

redux中通过createStore可以创建出store实例,在该实例上存在三个是实例方法。

  • 通过store.subscribe可以监听到state的改变,我们可以在这个方法中重新渲染组件,从而达到更新视图的效果。
  • 通过store.dispatch可以派发action,Store调用Reducer计算出新的state,若state产生变化,则会触发store.subscribe
  • 通过getState可以获取到redux内部的state
// index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store/index.js'

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

/** 监听store中的state变更 */
store.subscribe(()=> {
  render()
})

🧵 二、React-redux 介绍

redux是一个独立的第三方库,之后 React 官方在 redux 的基础上推出了 react-redux: 最新版的react-redux,全面拥抱了hooks,提供了一些hooks

  • Provider 组件包裹 App 提供 store
  • useSelector 钩子从 store 中提取数据
  • useDispatch 钩子来分发 action
  • useStore

react-redux集成图 image.png

示例:

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

const root = ReactDOM.createRoot(document.getElementById('root'));
function render() {
  root.render(
    <React.StrictMode>
      {/* 通过Provider将store传递到各个组件中 */}
      <Provider store={store}>
        <App  />
      </Provider>
    </React.StrictMode>
  );
}
render();

/** 监听store中的state变更 */
store.subscribe(()=> {
  render()
})
// App.jsx
import { addNum, subNum, setNum} from './store/actions/index.js'
// 引入react-redux提供的hooks
import { useSelector, useDispatch, useStore } from 'react-redux'

function App () {
  const dispatch = useDispatch();
  const count = useSelector(state=> state.count)
  console.log(useStore());
  
  const add = ()=> {
    dispatch(addNum())
  }

  const sub = ()=> {
    dispatch(subNum())
  }

  const set = (num)=> {
    dispatch(setNum(num))
  }
  return (
    <div id='root'>
      <div>
        <span>计数器:{count}</span>
        <button onClick={add}>加1</button>
        <button onClick={sub}>减1</button>
        <button onClick={()=> set(100)}>100</button>
        <button onClick={()=> set(200)}>200</button>
      </div>
    </div >
  );
}
export default App;

🛠 三、在React中集成react-redux + @reduxjs/toolkit

redux 本身对大型项目的模板代码冗长,维护困难。Redux 团队推出了官方推荐工具库:react-redux@reduxjs/toolkit,来简化整个redux的使用,大幅度简化了流程。

Redux Toolkit 的主要功能:

  • configureStore():简化的 store 设置,具有良好的默认值
  • createSlice(): 使用更少的代码生成 reducer 和 action
  • Immer集成:可直接修改state
  • createAsyncThunk(): 简化的异步逻辑
  • DevTools 集成:对 Redux DevTools 的内置支持
  • RTK Query:数据获取和缓存

✅ 使用 Redux Toolkit 重构

1.安装

首先安装两个依赖

npm install @reduxjs/toolkit react-redux
2.创建Slice
// store/reducer/counterSlice.js
import { createSlice, createAsyncThunk } from '@/reduxjs/toolkit'

/** 处理异步请求*/
export const getUserList = createAsyncThunk(
  "/api/user/list",
  async (payload, thunkApi) => {
    const res = await fetch("/api/user/list", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    });
    const data = await res.json();
    thunkApi.dispatch(setUserList(data))
  }
)

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0
  },
  reducers: {
    addNum (state) {
      state.count++
    },
    
    subNum (state) {
      state.count--
    },
    
    setNum (state, action) {
      state.count = action.payload
    },
    
    /** 设置用户列表 */
    setUserList(state, action) {
      state.userList = action.payload
    }
  }
})
console.log(counterSlice,'counterSlice')
export const { addNum, subNum, setNum, setUserList } = counterSlice.actions
export default counterSlice.reducer
3.配置Store
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './reducer/counterSlice.js'

export default configureStore({
  reducer: {
    counter: counterReducer,
  },
})
4. 将store注入到组件中
// ....
import { Provider } from "react-redux";
// 引入仓库
import store from "./redux/store";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);
5.获取/更新store中的数据
// App.js
import { addNum, subNum, setNum } from './store/reducer/counterSlice.js'
import { useSelector,useDispatch, useStore } from 'react-redux'
function App (props) {
  const dispatch = useDispatch();
  const { count } = useSelector(state=> state.counter)
  console.log(useStore());
  
  const add = ()=> {
    dispatch(addNum())
  }

  const sub = ()=> {
    dispatch(subNum())
  }

  const set = (num)=> {
    dispatch(setNum(num))
  }
  return (
    <div id='root'>
      <div>
        <span>计数器:{count}</span>
        <button onClick={add}>加1</button>
        <button onClick={sub}>减1</button>
        <button onClick={()=> set(100)}>100</button>
        <button onClick={()=> set(200)}>200</button>
      </div>
    </div >
  );
}

export default App;

🎯 小结

  • Redux 提供了明确的状态管理方案,但写法繁琐
  • React-Redux 使 Redux 更易集成到 React 项目中
  • Redux Toolkit 极大简化了 Redux 的使用,并提升了开发效率

📌 推荐阅读

🔚 结语

Redux 曾经被质疑过冗长、繁琐,但在 Redux Toolkit 的加持下,状态管理变得更加现代和高效。对于中大型 React 项目来说,它依然是一个值得信赖的解决方案。