React Store
React Store 是一个基于 Redux Toolkit 的状态管理工具包,它提供了更简洁的 API 来创建和管理 Redux store。
特性
- 基于 Redux Toolkit 的状态管理
- 提供简洁的 API 来创建和管理 store
- 支持 TypeScript 类型推导
- 支持函数式和对象式的状态更新
- 支持状态合并和部分更新
- 轻量级,无依赖
安装
npm install @kazura/react-store
使用方法
创建 Store
import { createSlice } from '@kazura/react-store'
// 定义状态类型
interface UserState {
name: string
age: number
isLoggedIn: boolean
}
// 创建初始状态
const initialState: UserState = {
name: '',
age: 0,
isLoggedIn: false,
}
// 创建 slice
const { reducer, action } = createSlice<UserState>('user', initialState)
// 创建 actions
export const userActions = {
setName: action((name: string) => ({ name })),
setAge: action((age: number) => ({ age })),
login: action(() => ({ isLoggedIn: true })),
logout: action(() => ({ isLoggedIn: false })),
updateProfile: action((name: string, age: number) => ({ name, age })),
reset: action(() => initialState),
}
export { reducer as userReducer }
配置 Store
import { configureStore } from '@reduxjs/toolkit'
import { userReducer, userActions } from './user.slice'
const store = configureStore({
reducer: {
user: userReducer,
},
})
export { store, userActions }
在组件中使用
import { useSelector, useDispatch } from 'react-redux'
import { userActions } from './user.slice'
function UserProfile() {
const dispatch = useDispatch()
const user = useSelector((state: RootState) => state.user)
return (
<div>
<h1>User Profile</h1>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
<p>Status: {user.isLoggedIn ? 'Logged In' : 'Logged Out'}</p>
<button onClick={() => dispatch(userActions.setName('John'))}>Change Name</button>
<button onClick={() => dispatch(userActions.setAge(30))}>Change Age</button>
<button onClick={() => dispatch(userActions.login())}>Login</button>
<button onClick={() => dispatch(userActions.logout())}>Logout</button>
</div>
)
}
API 参考
createSlice
function createSlice<T>(
name: string,
initialState: T
): {
reducer: Reducer<T>
action: <Handel extends (...args: any[]) => Partial<T> | ((state: T) => Partial<T> | void)>(
handel: Handel
) => (...args: Parameters<Handel>) => PayloadAction<(state: T) => T | void>
}
创建一个 Redux slice。
参数:
name
: slice 名称initialState
: 初始状态
返回值:
- 包含 reducer 和 action 创建器的对象
类型定义
Draft
type Draft<T> = {
-readonly [P in keyof T]: Draft<T[P]>
}
用于创建可变的类型。
PayloadAction
interface PayloadAction<P = void, T extends string = string> {
payload: P
type: T
}
Redux action 类型。
注意事项
- 确保在使用 store 之前配置了 Redux store
- 使用 TypeScript 来获得更好的类型提示
- 可以使用函数式或对象式的状态更新
- 建议将相关的 actions 组织在一起
- 函数式更新可以访问完整的状态
- 对象式更新会自动合并状态
- 返回 undefined 的函数式更新不会改变状态
示例
创建复杂的 Store
import { createSlice } from '@kazura/react-store'
interface TodoState {
todos: { id: number; text: string; completed: boolean }[]
filter: 'all' | 'active' | 'completed'
}
const initialState: TodoState = {
todos: [],
filter: 'all',
}
const { reducer, action } = createSlice<TodoState>('todo', initialState)
export const todoActions = {
addTodo: action((text: string) => (state) => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }],
})),
toggleTodo: action((id: number) => (state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
removeTodo: action((id: number) => (state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
setFilter: action((filter: TodoState['filter']) => ({ filter })),
clearCompleted: action((state) => ({
todos: state.todos.filter((todo) => !todo.completed),
})),
}
export { reducer as todoReducer }
使用函数式更新
import { createSlice } from '@kazura/react-store'
interface CounterState {
count: number
history: number[]
}
const initialState: CounterState = {
count: 0,
history: [],
}
const { reducer, action } = createSlice<CounterState>('counter', initialState)
export const counterActions = {
increment: action(() => (state) => ({
count: state.count + 1,
history: [...state.history, state.count + 1],
})),
decrement: action(() => (state) => ({
count: state.count - 1,
history: [...state.history, state.count - 1],
})),
reset: action(() => initialState),
setCount: action((count: number) => (state) => ({
count,
history: [...state.history, count],
})),
}
export { reducer as counterReducer }
使用对象式更新
import { createSlice } from '@kazura/react-store'
interface SettingsState {
theme: 'light' | 'dark'
language: string
notifications: boolean
}
const initialState: SettingsState = {
theme: 'light',
language: 'en',
notifications: true,
}
const { reducer, action } = createSlice<SettingsState>('settings', initialState)
export const settingsActions = {
setTheme: action((theme: SettingsState['theme']) => ({ theme })),
setLanguage: action((language: string) => ({ language })),
toggleNotifications: action(() => (state) => ({
notifications: !state.notifications,
})),
reset: action(() => initialState),
}
export { reducer as settingsReducer }
组合多个 Store
import { configureStore } from '@reduxjs/toolkit'
import { userReducer, userActions } from './user.slice'
import { todoReducer, todoActions } from './todo.slice'
import { counterReducer, counterActions } from './counter.slice'
import { settingsReducer, settingsActions } from './settings.slice'
const store = configureStore({
reducer: {
user: userReducer,
todo: todoReducer,
counter: counterReducer,
settings: settingsReducer,
},
})
export { store, userActions, todoActions, counterActions, settingsActions }