初始化工程
This commit is contained in:
199
src/store/README.md
Normal file
199
src/store/README.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# 用户状态管理使用说明
|
||||
|
||||
本项目使用 Zustand 进行用户状态管理,提供简洁、高效的用户信息管理解决方案。
|
||||
|
||||
## 主要特性
|
||||
|
||||
- 🚀 简单易用:无需 Provider 包装,直接使用 hooks
|
||||
- 🔄 自动持久化:状态变化自动保存到本地存储
|
||||
- 🎯 TypeScript 友好:完整的类型支持
|
||||
- 👥 团队协作:清晰的状态结构,易于维护
|
||||
- 📊 实时统计:自动记录用户活动和 API 请求
|
||||
|
||||
## 基本使用
|
||||
|
||||
### 1. 获取用户信息
|
||||
|
||||
```tsx
|
||||
import { useUserInfo, useUserStats, useIsLoggedIn } from '../store/userStore'
|
||||
|
||||
function MyComponent() {
|
||||
// 获取用户信息
|
||||
const userInfo = useUserInfo()
|
||||
|
||||
// 获取用户统计数据
|
||||
const userStats = useUserStats()
|
||||
|
||||
// 获取登录状态
|
||||
const isLoggedIn = useIsLoggedIn()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>欢迎 {userInfo?.username}!</h1>
|
||||
<p>API 请求次数: {userStats.requestCount}</p>
|
||||
<p>登录状态: {isLoggedIn ? '已登录' : '未登录'}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 修改用户信息
|
||||
|
||||
```tsx
|
||||
import { useUserActions } from '../store/userStore'
|
||||
|
||||
function MyComponent() {
|
||||
const {
|
||||
updateUserInfo,
|
||||
incrementRequestCount,
|
||||
incrementMatchesCreated
|
||||
} = useUserActions()
|
||||
|
||||
const handleUpdateUsername = () => {
|
||||
updateUserInfo('username', '新用户名')
|
||||
}
|
||||
|
||||
const handleApiRequest = () => {
|
||||
incrementRequestCount() // API 请求计数 +1
|
||||
}
|
||||
|
||||
const handleCreateMatch = () => {
|
||||
incrementMatchesCreated() // 创建比赛计数 +1
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={handleUpdateUsername}>更新用户名</button>
|
||||
<button onClick={handleApiRequest}>发送 API 请求</button>
|
||||
<button onClick={handleCreateMatch}>创建比赛</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 模拟 API 请求示例
|
||||
|
||||
```tsx
|
||||
import { useState } from 'react'
|
||||
import { useUserActions } from '../store/userStore'
|
||||
|
||||
function MyComponent() {
|
||||
const { incrementRequestCount } = useUserActions()
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handleSendRequest = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
// 模拟网络延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
// 更新请求计数
|
||||
incrementRequestCount()
|
||||
|
||||
console.log('请求成功!')
|
||||
} catch (error) {
|
||||
console.error('请求失败:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={handleSendRequest} disabled={loading}>
|
||||
{loading ? '发送中...' : '发送请求'}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 数据结构
|
||||
|
||||
### UserInfo 接口
|
||||
|
||||
```typescript
|
||||
interface UserInfo {
|
||||
id: string // 用户唯一标识
|
||||
username: string // 用户名
|
||||
avatar: string // 头像 URL
|
||||
phone: string // 手机号
|
||||
email: string // 邮箱
|
||||
location: string // 位置
|
||||
ntrpLevel: number // NTRP 等级
|
||||
joinDate: string // 加入日期
|
||||
totalMatches: number // 总比赛数
|
||||
winRate: number // 胜率
|
||||
}
|
||||
```
|
||||
|
||||
### UserStats 接口
|
||||
|
||||
```typescript
|
||||
interface UserStats {
|
||||
requestCount: number // API 请求次数
|
||||
matchesCreated: number // 创建的比赛数量
|
||||
matchesJoined: number // 参加的比赛数量
|
||||
lastActiveTime: string // 最后活跃时间
|
||||
}
|
||||
```
|
||||
|
||||
## 可用的 Actions
|
||||
|
||||
| Action | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| `setUserInfo(userInfo)` | userInfo: UserInfo | 设置用户信息 |
|
||||
| `updateUserInfo(field, value)` | field: keyof UserInfo, value: any | 更新用户信息字段 |
|
||||
| `clearUserInfo()` | 无 | 清除用户信息(登出) |
|
||||
| `incrementRequestCount()` | 无 | API 请求计数 +1 |
|
||||
| `incrementMatchesCreated()` | 无 | 创建比赛计数 +1 |
|
||||
| `incrementMatchesJoined()` | 无 | 参加比赛计数 +1 |
|
||||
| `updateLastActiveTime()` | 无 | 更新最后活跃时间 |
|
||||
| `resetUserStats()` | 无 | 重置用户统计数据 |
|
||||
| `setLoading(loading)` | loading: boolean | 设置加载状态 |
|
||||
|
||||
## 本地存储
|
||||
|
||||
- 用户信息保存键值:`user_info`
|
||||
- 用户统计保存键值:`user_stats`
|
||||
- 所有状态变化会自动保存到本地存储
|
||||
- 应用启动时自动加载保存的数据
|
||||
|
||||
## 便捷 Hooks
|
||||
|
||||
| Hook | 返回值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `useUserInfo()` | UserInfo \| null | 获取用户信息 |
|
||||
| `useUserStats()` | UserStats | 获取用户统计 |
|
||||
| `useIsLoggedIn()` | boolean | 获取登录状态 |
|
||||
| `useUserActions()` | Actions | 获取所有操作函数 |
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **优先使用专用 hooks**:使用 `useUserInfo()` 和 `useUserActions()` 而不是完整的 `useUserStore()`
|
||||
2. **按需获取**:只获取组件需要的状态,避免不必要的重渲染
|
||||
3. **类型安全**:充分利用 TypeScript 类型检查,避免字段名错误
|
||||
4. **数据纯净**:状态管理只处理数据,不包含业务逻辑
|
||||
5. **及时更新**:用户操作后及时更新相关统计数据
|
||||
|
||||
## 使用示例
|
||||
|
||||
查看 `src/pages/index/index.tsx` 获取完整的使用示例,包括:
|
||||
|
||||
- 用户信息展示
|
||||
- 统计数据实时更新
|
||||
- API 请求模拟
|
||||
- 加载状态管理
|
||||
- 数据持久化演示
|
||||
|
||||
## 扩展建议
|
||||
|
||||
如需添加新的用户状态或功能:
|
||||
|
||||
1. 在 `UserInfo` 或 `UserStats` 接口中添加新字段
|
||||
2. 在 store 的初始状态中设置默认值
|
||||
3. 添加相应的 action 函数
|
||||
4. 导出便捷的 hooks(如果需要)
|
||||
|
||||
这种设计让用户状态管理既简单又强大,非常适合团队协作开发。
|
||||
39
src/store/storage.ts
Normal file
39
src/store/storage.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import Taro from '@tarojs/taro'
|
||||
|
||||
// 通用存储工具函数
|
||||
export const setStorage = (key: string, data: any) => {
|
||||
try {
|
||||
Taro.setStorageSync(key, JSON.stringify(data))
|
||||
} catch (error) {
|
||||
console.error('保存数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
export const getStorage = <T>(key: string): T | null => {
|
||||
try {
|
||||
const data = Taro.getStorageSync(key)
|
||||
if (data) {
|
||||
return JSON.parse(data)
|
||||
}
|
||||
return null
|
||||
} catch (error) {
|
||||
console.error('读取数据失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const removeStorage = (key: string) => {
|
||||
try {
|
||||
Taro.removeStorageSync(key)
|
||||
} catch (error) {
|
||||
console.error('清除数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
export const clearAllStorage = () => {
|
||||
try {
|
||||
Taro.clearStorageSync()
|
||||
} catch (error) {
|
||||
console.error('清除所有数据失败:', error)
|
||||
}
|
||||
}
|
||||
58
src/store/userStore.ts
Normal file
58
src/store/userStore.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { create } from 'zustand'
|
||||
|
||||
// 用户统计信息
|
||||
export interface UserStats {
|
||||
requestCount: number
|
||||
matchesCreated: number
|
||||
matchesJoined: number
|
||||
lastActiveTime: string
|
||||
}
|
||||
|
||||
// Store 状态接口
|
||||
interface UserState {
|
||||
userStats: UserStats
|
||||
incrementRequestCount: () => void
|
||||
resetUserStats: () => void
|
||||
}
|
||||
|
||||
// 创建适配 Zustand 4.x 的 store
|
||||
export const useUserStore = create<UserState>()((set) => ({
|
||||
// 初始状态
|
||||
userStats: {
|
||||
requestCount: 0,
|
||||
matchesCreated: 0,
|
||||
matchesJoined: 0,
|
||||
lastActiveTime: new Date().toISOString()
|
||||
},
|
||||
|
||||
// Actions
|
||||
incrementRequestCount: () => {
|
||||
console.log('store: incrementRequestCount 被调用')
|
||||
set((state) => ({
|
||||
userStats: {
|
||||
...state.userStats,
|
||||
requestCount: state.userStats.requestCount + 1,
|
||||
lastActiveTime: new Date().toISOString()
|
||||
}
|
||||
}))
|
||||
},
|
||||
|
||||
resetUserStats: () => {
|
||||
console.log('store: resetUserStats 被调用')
|
||||
set({
|
||||
userStats: {
|
||||
requestCount: 0,
|
||||
matchesCreated: 0,
|
||||
matchesJoined: 0,
|
||||
lastActiveTime: new Date().toISOString()
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
// 简单的 hooks
|
||||
export const useUserStats = () => useUserStore((state) => state.userStats)
|
||||
export const useUserActions = () => useUserStore((state) => ({
|
||||
incrementRequestCount: state.incrementRequestCount,
|
||||
resetUserStats: state.resetUserStats
|
||||
}))
|
||||
Reference in New Issue
Block a user