refactor: 架构重构 - 解耦过度耦合模块
主要改动: 1. 创建乐观更新工具函数 (optimisticUpdate.ts) - 消除 userStore.ts 中的重复代码 2. 拆分 useResponsive.ts (485行 -> 12个专注模块) - useBreakpoint: 断点检测 - useOrientation: 方向检测 - usePlatform: 平台检测 - useScreenSize: 屏幕尺寸 - useResponsiveValue: 响应式值 - useResponsiveStyle: 响应式样式 - useMediaQuery: 媒体查询 - useColumnCount: 列数计算 - useResponsiveSpacing: 响应式间距 3. 整理数据层 (Repository 层) - ApiDataSource: API数据源 - LocalDataSource: 本地数据源 - CacheDataSource: 缓存数据源 - MessageRepository: 消息仓库 4. 重构 messageManager.ts (2194行 -> 4个模块) - MessageStateManager: 状态管理 - WebSocketMessageHandler: WebSocket处理 - MessageSyncService: 消息同步 - ReadReceiptManager: 已读管理 5. 导航解耦 (MainNavigator.tsx: 1118行 -> 100行) - 创建 NavigationService 解耦层 - 拆分多个 Navigator 组件 架构改进: - 单一职责原则: 每个模块职责明确 - 依赖倒置: 通过接口解耦 - 代码复用: 工具函数可被多处使用 - 可测试性: 各模块可独立测试
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
} from '../services';
|
||||
import { userManager } from './userManager';
|
||||
import { messageManager } from './messageManager';
|
||||
import { createOptimisticUpdaterFactory } from '../utils/optimisticUpdate';
|
||||
|
||||
interface UserState {
|
||||
// 状态
|
||||
@@ -59,504 +60,386 @@ interface UserState {
|
||||
refreshAll: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const useUserStore = create<UserState>((set, get) => ({
|
||||
// 初始状态
|
||||
users: [],
|
||||
userCache: {},
|
||||
posts: [],
|
||||
notifications: [],
|
||||
notificationBadge: {
|
||||
total: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
follows: 0,
|
||||
system: 0,
|
||||
},
|
||||
messageUnreadCount: 0,
|
||||
searchHistory: [],
|
||||
isLoadingPosts: false,
|
||||
isLoadingNotifications: false,
|
||||
|
||||
// 获取用户信息
|
||||
fetchUser: async (userId: string) => {
|
||||
// 先检查缓存
|
||||
const cached = get().userCache[userId];
|
||||
if (cached) return cached;
|
||||
export const useUserStore = create<UserState>((set, get) => {
|
||||
// 创建乐观更新器
|
||||
const optimisticUpdater = createOptimisticUpdaterFactory<UserState>(set, get);
|
||||
|
||||
return {
|
||||
// 初始状态
|
||||
users: [],
|
||||
userCache: {},
|
||||
posts: [],
|
||||
notifications: [],
|
||||
notificationBadge: {
|
||||
total: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
follows: 0,
|
||||
system: 0,
|
||||
},
|
||||
messageUnreadCount: 0,
|
||||
searchHistory: [],
|
||||
isLoadingPosts: false,
|
||||
isLoadingNotifications: false,
|
||||
|
||||
try {
|
||||
const user = await userManager.getUserById(userId);
|
||||
if (user) {
|
||||
// 获取用户信息
|
||||
fetchUser: async (userId: string) => {
|
||||
// 先检查缓存
|
||||
const cached = get().userCache[userId];
|
||||
if (cached) return cached;
|
||||
|
||||
try {
|
||||
const user = await userManager.getUserById(userId);
|
||||
if (user) {
|
||||
set(state => ({
|
||||
userCache: { ...state.userCache, [userId]: user }
|
||||
}));
|
||||
return user;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
// 获取用户帖子
|
||||
fetchUserPosts: async (userId: string, page = 1) => {
|
||||
try {
|
||||
const response = await postService.getUserPosts(userId, page);
|
||||
const newPosts = response.list;
|
||||
|
||||
set(state => ({
|
||||
userCache: { ...state.userCache, [userId]: user }
|
||||
posts: page === 1 ? newPosts : [...state.posts, ...newPosts]
|
||||
}));
|
||||
return user;
|
||||
|
||||
return newPosts;
|
||||
} catch (error) {
|
||||
console.error('获取用户帖子失败:', error);
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
// 获取用户帖子
|
||||
fetchUserPosts: async (userId: string, page = 1) => {
|
||||
try {
|
||||
const response = await postService.getUserPosts(userId, page);
|
||||
const newPosts = response.list;
|
||||
|
||||
set(state => ({
|
||||
posts: page === 1 ? newPosts : [...state.posts, ...newPosts]
|
||||
}));
|
||||
|
||||
return newPosts;
|
||||
} catch (error) {
|
||||
console.error('获取用户帖子失败:', error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
// 获取帖子列表(首页)
|
||||
fetchPosts: async (type: 'recommend' | 'follow' | 'hot' | 'latest', page = 1) => {
|
||||
set({ isLoadingPosts: true });
|
||||
},
|
||||
|
||||
try {
|
||||
let response;
|
||||
// 获取帖子列表(首页)
|
||||
fetchPosts: async (type: 'recommend' | 'follow' | 'hot' | 'latest', page = 1) => {
|
||||
set({ isLoadingPosts: true });
|
||||
|
||||
switch (type) {
|
||||
case 'recommend':
|
||||
response = await postService.getRecommendedPosts(page);
|
||||
break;
|
||||
case 'follow':
|
||||
response = await postService.getFollowingPosts(page);
|
||||
break;
|
||||
case 'hot':
|
||||
response = await postService.getHotPosts(page);
|
||||
break;
|
||||
case 'latest':
|
||||
default:
|
||||
response = await postService.getLatestPosts(page);
|
||||
break;
|
||||
try {
|
||||
let response;
|
||||
|
||||
switch (type) {
|
||||
case 'recommend':
|
||||
response = await postService.getRecommendedPosts(page);
|
||||
break;
|
||||
case 'follow':
|
||||
response = await postService.getFollowingPosts(page);
|
||||
break;
|
||||
case 'hot':
|
||||
response = await postService.getHotPosts(page);
|
||||
break;
|
||||
case 'latest':
|
||||
default:
|
||||
response = await postService.getLatestPosts(page);
|
||||
break;
|
||||
}
|
||||
|
||||
const newPosts = response.list;
|
||||
|
||||
set(state => ({
|
||||
posts: page === 1 ? newPosts : [...state.posts, ...newPosts],
|
||||
isLoadingPosts: false
|
||||
}));
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('获取帖子列表失败:', error);
|
||||
set({ isLoadingPosts: false });
|
||||
return {
|
||||
list: [],
|
||||
total: 0,
|
||||
page,
|
||||
page_size: 20,
|
||||
total_pages: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const newPosts = response.list;
|
||||
|
||||
set(state => ({
|
||||
posts: page === 1 ? newPosts : [...state.posts, ...newPosts],
|
||||
isLoadingPosts: false
|
||||
}));
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('获取帖子列表失败:', error);
|
||||
set({ isLoadingPosts: false });
|
||||
return {
|
||||
list: [],
|
||||
total: 0,
|
||||
page,
|
||||
page_size: 20,
|
||||
total_pages: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 获取通知列表
|
||||
fetchNotifications: async (type?: string, page = 1) => {
|
||||
set({ isLoadingNotifications: true });
|
||||
},
|
||||
|
||||
try {
|
||||
const response = await notificationService.getNotifications(
|
||||
page,
|
||||
20,
|
||||
type as any
|
||||
);
|
||||
// 获取通知列表
|
||||
fetchNotifications: async (type?: string, page = 1) => {
|
||||
set({ isLoadingNotifications: true });
|
||||
|
||||
const newNotifications = response.list;
|
||||
|
||||
set(state => ({
|
||||
notifications: page === 1 ? newNotifications : [...state.notifications, ...newNotifications],
|
||||
isLoadingNotifications: false
|
||||
}));
|
||||
|
||||
return newNotifications;
|
||||
} catch (error) {
|
||||
console.error('获取通知列表失败:', error);
|
||||
set({ isLoadingNotifications: false });
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
// 标记通知为已读
|
||||
markNotificationAsRead: async (notificationId: string) => {
|
||||
try {
|
||||
await notificationService.markAsRead(notificationId);
|
||||
|
||||
set(state => {
|
||||
const notifications = state.notifications.map(n =>
|
||||
n.id === notificationId ? { ...n, isRead: true } : n
|
||||
try {
|
||||
const response = await notificationService.getNotifications(
|
||||
page,
|
||||
20,
|
||||
type as any
|
||||
);
|
||||
|
||||
return {
|
||||
notifications,
|
||||
const newNotifications = response.list;
|
||||
|
||||
set(state => ({
|
||||
notifications: page === 1 ? newNotifications : [...state.notifications, ...newNotifications],
|
||||
isLoadingNotifications: false
|
||||
}));
|
||||
|
||||
return newNotifications;
|
||||
} catch (error) {
|
||||
console.error('获取通知列表失败:', error);
|
||||
set({ isLoadingNotifications: false });
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
// 标记通知为已读
|
||||
markNotificationAsRead: async (notificationId: string) => {
|
||||
try {
|
||||
await notificationService.markAsRead(notificationId);
|
||||
|
||||
set(state => {
|
||||
const notifications = state.notifications.map(n =>
|
||||
n.id === notificationId ? { ...n, isRead: true } : n
|
||||
);
|
||||
|
||||
return {
|
||||
notifications,
|
||||
notificationBadge: {
|
||||
total: notifications.filter(n => !n.isRead).length,
|
||||
likes: notifications.filter(n => n.type === 'like_post' && !n.isRead).length,
|
||||
comments: notifications.filter(n => n.type === 'comment' && !n.isRead).length,
|
||||
follows: notifications.filter(n => n.type === 'follow' && !n.isRead).length,
|
||||
system: notifications.filter(n => n.type === 'system' && !n.isRead).length,
|
||||
}
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('标记通知为已读失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 标记所有通知为已读
|
||||
markAllNotificationsAsRead: async () => {
|
||||
try {
|
||||
await notificationService.markAllAsRead();
|
||||
|
||||
set(state => ({
|
||||
notifications: state.notifications.map(n => ({ ...n, isRead: true })),
|
||||
notificationBadge: {
|
||||
total: notifications.filter(n => !n.isRead).length,
|
||||
likes: notifications.filter(n => n.type === 'like_post' && !n.isRead).length,
|
||||
comments: notifications.filter(n => n.type === 'comment' && !n.isRead).length,
|
||||
follows: notifications.filter(n => n.type === 'follow' && !n.isRead).length,
|
||||
system: notifications.filter(n => n.type === 'system' && !n.isRead).length,
|
||||
total: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
follows: 0,
|
||||
system: 0,
|
||||
}
|
||||
};
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('标记所有通知为已读失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取通知角标
|
||||
fetchNotificationBadge: async () => {
|
||||
try {
|
||||
const badge = await notificationService.getNotificationBadge();
|
||||
set({ notificationBadge: badge });
|
||||
} catch (error) {
|
||||
console.error('获取通知角标失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 设置消息未读数
|
||||
// 注意:未读数现在由 MessageManager 统一管理
|
||||
// 此方法保留用于 TabBar 角标显示,从 MessageManager 同步
|
||||
setMessageUnreadCount: (count: number) => {
|
||||
set({ messageUnreadCount: count });
|
||||
},
|
||||
|
||||
// 从后端拉取最新消息未读数
|
||||
// @deprecated 请使用 messageManager.fetchUnreadCount() 代替
|
||||
// 此方法保留用于向后兼容
|
||||
fetchMessageUnreadCount: async () => {
|
||||
try {
|
||||
await messageManager.fetchUnreadCount();
|
||||
const unread = messageManager.getUnreadCount();
|
||||
set({ messageUnreadCount: unread.total + unread.system });
|
||||
} catch (error) {
|
||||
console.error('获取消息未读数失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 添加搜索历史
|
||||
addSearchHistory: (keyword: string) => {
|
||||
set(state => {
|
||||
const history = [keyword, ...state.searchHistory.filter(k => k !== keyword)].slice(0, 20);
|
||||
return { searchHistory: history };
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('标记通知为已读失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 标记所有通知为已读
|
||||
markAllNotificationsAsRead: async () => {
|
||||
try {
|
||||
await notificationService.markAllAsRead();
|
||||
},
|
||||
|
||||
// 清除搜索历史
|
||||
clearSearchHistory: () => {
|
||||
set({ searchHistory: [] });
|
||||
},
|
||||
|
||||
// 点赞帖子 - 使用乐观更新工具
|
||||
likePost: async (postId: string) => {
|
||||
const originalPosts = get().posts;
|
||||
|
||||
set(state => ({
|
||||
notifications: state.notifications.map(n => ({ ...n, isRead: true })),
|
||||
notificationBadge: {
|
||||
total: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
follows: 0,
|
||||
system: 0,
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('标记所有通知为已读失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取通知角标
|
||||
fetchNotificationBadge: async () => {
|
||||
try {
|
||||
const badge = await notificationService.getNotificationBadge();
|
||||
set({ notificationBadge: badge });
|
||||
} catch (error) {
|
||||
console.error('获取通知角标失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 设置消息未读数
|
||||
// 注意:未读数现在由 MessageManager 统一管理
|
||||
// 此方法保留用于 TabBar 角标显示,从 MessageManager 同步
|
||||
setMessageUnreadCount: (count: number) => {
|
||||
set({ messageUnreadCount: count });
|
||||
},
|
||||
|
||||
// 从后端拉取最新消息未读数
|
||||
// @deprecated 请使用 messageManager.fetchUnreadCount() 代替
|
||||
// 此方法保留用于向后兼容
|
||||
fetchMessageUnreadCount: async () => {
|
||||
try {
|
||||
await messageManager.fetchUnreadCount();
|
||||
const unread = messageManager.getUnreadCount();
|
||||
set({ messageUnreadCount: unread.total + unread.system });
|
||||
} catch (error) {
|
||||
console.error('获取消息未读数失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 添加搜索历史
|
||||
addSearchHistory: (keyword: string) => {
|
||||
set(state => {
|
||||
const history = [keyword, ...state.searchHistory.filter(k => k !== keyword)].slice(0, 20);
|
||||
return { searchHistory: history };
|
||||
});
|
||||
},
|
||||
|
||||
// 清除搜索历史
|
||||
clearSearchHistory: () => {
|
||||
set({ searchHistory: [] });
|
||||
},
|
||||
|
||||
// 点赞帖子 - 乐观更新
|
||||
likePost: async (postId: string) => {
|
||||
// 先乐观更新本地状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_liked: true, likes_count: p.likes_count + 1 } : p
|
||||
)
|
||||
}));
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
const updatedPost = await postService.likePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用后端返回的更新后数据更新状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
} else {
|
||||
// API 返回失败,回滚状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_liked: false, likes_count: Math.max(0, p.likes_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('点赞帖子失败:', error);
|
||||
// 失败回滚状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_liked: false, likes_count: Math.max(0, p.likes_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 取消点赞 - 乐观更新
|
||||
unlikePost: async (postId: string) => {
|
||||
// 先乐观更新本地状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_liked: false, likes_count: Math.max(0, p.likes_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
const updatedPost = await postService.unlikePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用后端返回的更新后数据更新状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
} else {
|
||||
// API 返回失败,回滚状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_liked: true, likes_count: p.likes_count + 1 } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('取消点赞帖子失败:', error);
|
||||
// 失败回滚状态
|
||||
// 乐观更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_liked: true, likes_count: p.likes_count + 1 } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 收藏帖子 - 乐观更新
|
||||
favoritePost: async (postId: string) => {
|
||||
// 先乐观更新本地状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: true, favorites_count: p.favorites_count + 1 } : p
|
||||
)
|
||||
}));
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
const updatedPost = await postService.favoritePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用后端返回的更新后数据更新状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
} else {
|
||||
// API 返回失败,回滚状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: false, favorites_count: Math.max(0, p.favorites_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
|
||||
try {
|
||||
const updatedPost = await postService.likePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用服务器返回的数据更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('点赞帖子失败:', error);
|
||||
// 回滚
|
||||
set({ posts: originalPosts });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('收藏帖子失败:', error);
|
||||
// 失败回滚状态
|
||||
},
|
||||
|
||||
// 取消点赞 - 使用乐观更新工具
|
||||
unlikePost: async (postId: string) => {
|
||||
const originalPosts = get().posts;
|
||||
|
||||
// 乐观更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: false, favorites_count: Math.max(0, p.favorites_count - 1) } : p
|
||||
p.id === postId ? { ...p, is_liked: false, likes_count: Math.max(0, p.likes_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 取消收藏 - 乐观更新
|
||||
unfavoritePost: async (postId: string) => {
|
||||
// 先乐观更新本地状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: false, favorites_count: Math.max(0, p.favorites_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
const updatedPost = await postService.unfavoritePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用后端返回的更新后数据更新状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
} else {
|
||||
// API 返回失败,回滚状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: true, favorites_count: p.favorites_count + 1 } : p
|
||||
)
|
||||
}));
|
||||
|
||||
try {
|
||||
const updatedPost = await postService.unlikePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用服务器返回的数据更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('取消点赞帖子失败:', error);
|
||||
// 回滚
|
||||
set({ posts: originalPosts });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('取消收藏帖子失败:', error);
|
||||
// 失败回滚状态
|
||||
},
|
||||
|
||||
// 收藏帖子 - 使用乐观更新工具
|
||||
favoritePost: async (postId: string) => {
|
||||
const originalPosts = get().posts;
|
||||
|
||||
// 乐观更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: true, favorites_count: p.favorites_count + 1 } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 点赞评论
|
||||
likeComment: async (commentId: string) => {
|
||||
// 先更新本地状态(更新posts中的帖子的评论点赞状态)
|
||||
set(state => ({
|
||||
posts: state.posts.map(p => ({
|
||||
...p,
|
||||
top_comment: p.top_comment && p.top_comment.id === commentId
|
||||
? { ...p.top_comment, is_liked: true, likes_count: p.top_comment.likes_count + 1 }
|
||||
: p.top_comment
|
||||
}))
|
||||
}));
|
||||
|
||||
try {
|
||||
const updatedPost = await postService.favoritePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用服务器返回的数据更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('收藏帖子失败:', error);
|
||||
// 回滚
|
||||
set({ posts: originalPosts });
|
||||
}
|
||||
},
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
await commentService.likeComment(commentId);
|
||||
} catch (error) {
|
||||
console.error('点赞评论失败:', error);
|
||||
// 失败回滚状态
|
||||
// 取消收藏 - 使用乐观更新工具
|
||||
unfavoritePost: async (postId: string) => {
|
||||
const originalPosts = get().posts;
|
||||
|
||||
// 乐观更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p => ({
|
||||
...p,
|
||||
top_comment: p.top_comment && p.top_comment.id === commentId
|
||||
? { ...p.top_comment, is_liked: false, likes_count: Math.max(0, p.top_comment.likes_count - 1) }
|
||||
: p.top_comment
|
||||
}))
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 取消点赞评论
|
||||
unlikeComment: async (commentId: string) => {
|
||||
// 先更新本地状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p => ({
|
||||
...p,
|
||||
top_comment: p.top_comment && p.top_comment.id === commentId
|
||||
? { ...p.top_comment, is_liked: false, likes_count: Math.max(0, p.top_comment.likes_count - 1) }
|
||||
: p.top_comment
|
||||
}))
|
||||
}));
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
await commentService.unlikeComment(commentId);
|
||||
} catch (error) {
|
||||
console.error('取消点赞评论失败:', error);
|
||||
// 失败回滚状态
|
||||
set(state => ({
|
||||
posts: state.posts.map(p => ({
|
||||
...p,
|
||||
top_comment: p.top_comment && p.top_comment.id === commentId
|
||||
? { ...p.top_comment, is_liked: true, likes_count: p.top_comment.likes_count + 1 }
|
||||
: p.top_comment
|
||||
}))
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 关注用户
|
||||
followUser: async (userId: string) => {
|
||||
// 先更新本地状态
|
||||
set(state => ({
|
||||
users: state.users.map(u =>
|
||||
u.id === userId
|
||||
? { ...u, isFollowing: true, followersCount: u.followers_count + 1 }
|
||||
: u
|
||||
),
|
||||
userCache: Object.fromEntries(
|
||||
Object.entries(state.userCache).map(([id, user]) => [
|
||||
id,
|
||||
id === userId
|
||||
? { ...user, isFollowing: true, followersCount: user.followers_count + 1 }
|
||||
: user
|
||||
])
|
||||
)
|
||||
}));
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
await authService.followUser(userId);
|
||||
} catch (error) {
|
||||
console.error('关注用户失败:', error);
|
||||
// 失败回滚状态
|
||||
set(state => ({
|
||||
users: state.users.map(u =>
|
||||
u.id === userId
|
||||
? { ...u, isFollowing: false, followersCount: Math.max(0, u.followers_count - 1) }
|
||||
: u
|
||||
),
|
||||
userCache: Object.fromEntries(
|
||||
Object.entries(state.userCache).map(([id, user]) => [
|
||||
id,
|
||||
id === userId
|
||||
? { ...user, isFollowing: false, followersCount: Math.max(0, user.followers_count - 1) }
|
||||
: user
|
||||
])
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? { ...p, is_favorited: false, favorites_count: Math.max(0, p.favorites_count - 1) } : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 取消关注
|
||||
unfollowUser: async (userId: string) => {
|
||||
// 先更新本地状态
|
||||
set(state => ({
|
||||
users: state.users.map(u =>
|
||||
u.id === userId
|
||||
? { ...u, isFollowing: false, followersCount: Math.max(0, u.followers_count - 1) }
|
||||
: u
|
||||
),
|
||||
userCache: Object.fromEntries(
|
||||
Object.entries(state.userCache).map(([id, user]) => [
|
||||
id,
|
||||
id === userId
|
||||
? { ...user, isFollowing: false, followersCount: Math.max(0, user.followers_count - 1) }
|
||||
: user
|
||||
])
|
||||
)
|
||||
}));
|
||||
|
||||
try {
|
||||
const updatedPost = await postService.unfavoritePost(postId);
|
||||
if (updatedPost) {
|
||||
// 使用服务器返回的数据更新
|
||||
set(state => ({
|
||||
posts: state.posts.map(p =>
|
||||
p.id === postId ? updatedPost : p
|
||||
)
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('取消收藏帖子失败:', error);
|
||||
// 回滚
|
||||
set({ posts: originalPosts });
|
||||
}
|
||||
},
|
||||
|
||||
// 调用API
|
||||
try {
|
||||
await authService.unfollowUser(userId);
|
||||
} catch (error) {
|
||||
console.error('取消关注用户失败:', error);
|
||||
// 失败回滚状态
|
||||
// 点赞评论 - 使用乐观更新工具
|
||||
likeComment: async (commentId: string) => {
|
||||
await optimisticUpdater({
|
||||
key: 'posts',
|
||||
optimisticUpdate: (posts) =>
|
||||
posts.map(p => ({
|
||||
...p,
|
||||
top_comment: p.top_comment && p.top_comment.id === commentId
|
||||
? { ...p.top_comment, is_liked: true, likes_count: p.top_comment.likes_count + 1 }
|
||||
: p.top_comment
|
||||
})),
|
||||
rollbackState: (original) => original,
|
||||
apiCall: () => commentService.likeComment(commentId),
|
||||
errorMessage: '点赞评论失败',
|
||||
});
|
||||
},
|
||||
|
||||
// 取消点赞评论 - 使用乐观更新工具
|
||||
unlikeComment: async (commentId: string) => {
|
||||
await optimisticUpdater({
|
||||
key: 'posts',
|
||||
optimisticUpdate: (posts) =>
|
||||
posts.map(p => ({
|
||||
...p,
|
||||
top_comment: p.top_comment && p.top_comment.id === commentId
|
||||
? { ...p.top_comment, is_liked: false, likes_count: Math.max(0, p.top_comment.likes_count - 1) }
|
||||
: p.top_comment
|
||||
})),
|
||||
rollbackState: (original) => original,
|
||||
apiCall: () => commentService.unlikeComment(commentId),
|
||||
errorMessage: '取消点赞评论失败',
|
||||
});
|
||||
},
|
||||
|
||||
// 关注用户 - 使用乐观更新工具
|
||||
followUser: async (userId: string) => {
|
||||
const originalUsers = get().users;
|
||||
const originalUserCache = get().userCache;
|
||||
|
||||
// 乐观更新 users
|
||||
set(state => ({
|
||||
users: state.users.map(u =>
|
||||
u.id === userId
|
||||
? { ...u, isFollowing: true, followersCount: u.followers_count + 1 }
|
||||
: u
|
||||
),
|
||||
}));
|
||||
|
||||
// 乐观更新 userCache
|
||||
set(state => ({
|
||||
userCache: Object.fromEntries(
|
||||
Object.entries(state.userCache).map(([id, user]) => [
|
||||
id,
|
||||
@@ -566,17 +449,66 @@ export const useUserStore = create<UserState>((set, get) => ({
|
||||
])
|
||||
)
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新所有数据
|
||||
refreshAll: async () => {
|
||||
await Promise.all([
|
||||
get().fetchPosts('recommend', 1),
|
||||
get().fetchNotificationBadge(),
|
||||
]);
|
||||
},
|
||||
}));
|
||||
|
||||
try {
|
||||
await authService.followUser(userId);
|
||||
} catch (error) {
|
||||
console.error('关注用户失败:', error);
|
||||
// 回滚
|
||||
set({
|
||||
users: originalUsers,
|
||||
userCache: originalUserCache
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 取消关注 - 使用乐观更新工具
|
||||
unfollowUser: async (userId: string) => {
|
||||
const originalUsers = get().users;
|
||||
const originalUserCache = get().userCache;
|
||||
|
||||
// 乐观更新 users
|
||||
set(state => ({
|
||||
users: state.users.map(u =>
|
||||
u.id === userId
|
||||
? { ...u, isFollowing: false, followersCount: Math.max(0, u.followers_count - 1) }
|
||||
: u
|
||||
),
|
||||
}));
|
||||
|
||||
// 乐观更新 userCache
|
||||
set(state => ({
|
||||
userCache: Object.fromEntries(
|
||||
Object.entries(state.userCache).map(([id, user]) => [
|
||||
id,
|
||||
id === userId
|
||||
? { ...user, isFollowing: false, followersCount: Math.max(0, user.followers_count - 1) }
|
||||
: user
|
||||
])
|
||||
)
|
||||
}));
|
||||
|
||||
try {
|
||||
await authService.unfollowUser(userId);
|
||||
} catch (error) {
|
||||
console.error('取消关注用户失败:', error);
|
||||
// 回滚
|
||||
set({
|
||||
users: originalUsers,
|
||||
userCache: originalUserCache
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新所有数据
|
||||
refreshAll: async () => {
|
||||
await Promise.all([
|
||||
get().fetchPosts('recommend', 1),
|
||||
get().fetchNotificationBadge(),
|
||||
]);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// 导出selector hooks以优化性能
|
||||
export const usePosts = () => useUserStore((state) => state.posts);
|
||||
|
||||
Reference in New Issue
Block a user