作为一名前端开发人员,你或许对 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 由几个关键组件组成,它们协同工作以管理应用程序状态:
🔧 简单 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 提供 storeuseSelector
钩子从 store 中提取数据useDispatch
钩子来分发 actionuseStore
react-redux集成图
示例:
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 和 actionImmer集成
:可直接修改statecreateAsyncThunk():
简化的异步逻辑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 项目来说,它依然是一个值得信赖的解决方案。