一、Redux 三大核心概念
- Store:唯一数据源,整个应用只有一个 store,存放所有状态
- State:仓库里的数据,只读,不能直接修改
- Action :描述「要做什么」的普通对象,必须带
type属性(操作标识) - Reducer:纯函数,接收旧 state + action,返回新 state,唯一能改状态的地方
数据流:View 触发 dispatch(action) → Reducer 计算新 state → Store 更新 → View 更新
二、基础安装
bash
运行
bash
# 原生redux
npm install redux
# react项目配套
npm install redux react-redux
三、最简原生 Redux 完整示例(纯 JS)
1. 导入 createStore 创建仓库
js
javascript
import { createStore } from 'redux'
2. 定义初始 state
js
csharp
// 初始状态
const initState = {
count: 0,
user: { name: '' }
}
3. 编写 reducer 纯函数
规则:
- 不能修改原 state,必须返回全新对象
- 不能异步、定时器、随机数等副作用
- 参数:
(state, action) => newState
js
php
function reducer(state = initState, action) {
switch (action.type) {
case 'ADD':
// 返回新state,不能直接改state.count++
return {
...state,
count: state.count + 1
}
case 'SUB':
return {
...state,
count: state.count - 1
}
case 'SET_NAME':
return {
...state,
user: {
...state.user,
name: action.payload
}
}
default:
// 无匹配action返回原state
return state
}
}
4. 创建 store
js
ini
const store = createStore(reducer)
5. 四大基础 API(核心操作)
① store.getState () 获取当前所有状态
js
css
console.log(store.getState())
// { count:0, user:{name:''} }
② store.dispatch (action) 派发动作,修改状态
action 是对象,type 必传,payload 存放传递的数据
js
php
// 数字+1
store.dispatch({ type: 'ADD' })
// 数字-1
store.dispatch({ type: 'SUB' })
// 传入参数 payload
store.dispatch({ type: 'SET_NAME', payload: '张三' })
③ store.subscribe (回调) 监听 state 变化
state 更新就执行回调,常用于页面刷新
js
javascript
const unSubscribe = store.subscribe(() => {
console.log('状态更新了:', store.getState())
})
// 取消监听
unSubscribe()
④ 完整测试流程
js
php
// 监听
store.subscribe(() => {
console.log(store.getState())
})
// 派发action修改数据
store.dispatch({ type: 'ADD' })
store.dispatch({ type: 'ADD' })
store.dispatch({ type: 'SET_NAME', payload: '李四' })
四、规范封装 Action Creator(工厂函数)
手写 {type:xxx} 重复,封装函数生成 action
js
go
// action创建函数
const add = () => ({ type: 'ADD' })
const sub = () => ({ type: 'SUB' })
const setName = (name) => ({
type: 'SET_NAME',
payload: name
})
// 使用
store.dispatch(add())
store.dispatch(setName('老王'))
五、React 中使用:react-redux 基础
1. 顶层 Provider 注入 store
入口文件 main.js
js
javascript
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './reducer'
import App from './App'
const store = createStore(reducer)
ReactDOM.createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>
)
2. 函数组件:useSelector + useDispatch(hooks 推荐)
jsx
javascript
import { useSelector, useDispatch } from 'react-redux'
import { add, setName } from './action'
export default function Counter() {
// 读取state,自动订阅更新
const { count, user } = useSelector(state => state)
// 获取dispatch方法
const dispatch = useDispatch()
return (
<div>
<p>数字:{count}</p>
<p>姓名:{user.name}</p>
<button onClick={() => dispatch(add())}>+1</button>
<button onClick={() => dispatch(setName('小红'))}>改名</button>
</div>
)
}
3. 类组件 connect(老写法)
jsx
javascript
import { connect } from 'react-redux'
function App({ count, add }) {
return <button onClick={add}>{count}</button>
}
// mapStateToProps:把state映射为props
const mapState = state => ({
count: state.count
})
// mapDispatchToProps:把dispatch映射为props
const mapDispatch = { add }
export default connect(mapState, mapDispatch)(App)
六、拆分多模块 state(combineReducers)
项目大时拆分多个 reducer,合并成根 reducer
js
php
import { createStore, combineReducers } from 'redux'
// 计数器模块reducer
function countReducer(state = { num: 0 }, action) {
switch (action.type) {
case 'ADD': return { num: state.num + 1 }
default: return state
}
}
// 用户模块reducer
function userReducer(state = { name: '' }, action) {
switch (action.type) {
case 'SET_USER': return { name: action.payload }
default: return state
}
}
// 合并reducer
const rootReducer = combineReducers({
count: countReducer,
user: userReducer
})
const store = createStore(rootReducer)
// 获取数据时分层
const state = store.getState()
state.count.num
state.user.name
七、基础易错点总结
- reducer 绝对不能直接修改原 state,必须解构返回新对象 / 数组
- 只有 dispatch 能触发状态更新,直接
store.getState().count++无效 - action.type 全局唯一,多模块避免重名
- 异步请求(接口)原生 Redux 不支持,需要中间件 redux-thunk
- store 全局唯一,不能创建多个 store
八、异步基础(redux-thunk 最简)
原生 dispatch 只能传对象,thunk 支持传函数处理接口
bash
运行
npm install redux-thunk
js
javascript
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
const store = createStore(reducer, applyMiddleware(thunk))
// 异步action
const fetchUser = () => {
return async (dispatch) => {
const res = await fetch('/api/user')
const data = await res.json()
dispatch({ type: 'SET_USER', payload: data.name })
}
}
// 组件使用 dispatch(fetchUser())