Redux
Redux 基础
Redux 是 JavaScript 应用的可预测状态容器。它帮助您编写行为一致、可在不同环境中运行且易于测试的应用程序。
核心概念
- Store:保存应用状态的唯一数据源
- Actions:描述发生了什么的普通对象
- Reducers:指定状态如何响应 actions 而变化的纯函数
- Dispatch:触发状态变化的唯一方式
三大原则
- 单一数据源:全局状态存储在单一 store 中
- 状态只读:改变状态的唯一方式是触发 action
- 使用纯函数进行更改:Reducers 是接收先前状态和 action 并返回新状态的纯函数
设置 Redux
安装
npm install redux react-redux @reduxjs/toolkit
基本 Store 设置
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})
Actions 和 Action Creators
Actions 是将数据从应用发送到 store 的信息载荷。
// Action types
const INCREMENT = 'INCREMENT'
const DECREMENT = 'DECREMENT'
// Action creators
const increment = () => ({
type: INCREMENT,
})
const decrement = () => ({
type: DECREMENT,
})
const incrementByAmount = (amount) => ({
type: 'INCREMENT_BY_AMOUNT',
payload: amount,
})
Reducers
Reducers 指定应用状态如何响应 actions 而变化。
const initialState = {
value: 0,
}
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return {
...state,
value: state.value + 1,
}
case 'DECREMENT':
return {
...state,
value: state.value - 1,
}
case 'INCREMENT_BY_AMOUNT':
return {
...state,
value: state.value + action.payload,
}
default:
return state
}
}
Redux Toolkit (RTK)
Redux Toolkit 是官方的、开箱即用的高效 Redux 开发工具集。
创建 Slice
import { createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
连接 React 组件
使用 React-Redux Hooks
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement, incrementByAmount } from './counterSlice'
function Counter() {
const count = useSelector((state) => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<button onClick={() => dispatch(increment())}>+</button>
<span>{count}</span>
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
</div>
)
}
Provider 设置
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { store } from './store'
import App from './App'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
使用 Redux Thunk 处理异步操作
Thunk Action Creator
import { createAsyncThunk } from '@reduxjs/toolkit'
export const fetchUserById = createAsyncThunk('users/fetchById', async (userId) => {
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
在 Slice 中处理异步 Actions
const usersSlice = createSlice({
name: 'users',
initialState: {
entities: [],
loading: 'idle',
},
reducers: {
// standard reducer logic
},
extraReducers: (builder) => {
builder
.addCase(fetchUserById.pending, (state) => {
state.loading = 'pending'
})
.addCase(fetchUserById.fulfilled, (state, action) => {
state.loading = 'idle'
state.entities.push(action.payload)
})
.addCase(fetchUserById.rejected, (state) => {
state.loading = 'idle'
})
},
})
最佳实践
- 使用 Redux Toolkit:减少样板代码并包含实用工具
- 规范化状态结构:像数据库一样组织状态
- 保持状态最小化:仅将真正全局的数据放入 Redux
- 使用选择器:创建可复用的函数从状态中提取数据
- 拆分 Reducers:使用
combineReducers管理状态的不同部分
何时使用 Redux
Redux 在以下情况最有用:
- 应用有大量状态
- 状态频繁更新
- 更新状态的逻辑可能复杂
- 应用有中等或大型代码库
- 多个开发人员在应用上工作
常见模式
选择器函数
// 选择器
const selectCounter = (state) => state.counter.value
const selectCounterByAmount = (state, amount) => state.counter.value * amount
中间件
const loggerMiddleware = (store) => (next) => (action) => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
Redux 提供了一种可预测的方式来管理复杂应用中的状态,使调试更容易并启用强大的开发工具。