refactor(message): replace SubscriptionManager with Zustand selectors
All checks were successful
Frontend CI / ota-android (push) Successful in 11m17s
Frontend CI / build-and-push-web (push) Successful in 25m8s
Frontend CI / build-android-apk (push) Successful in 59m7s

Remove custom SubscriptionManager class and adopt Zustand's built-in
selector mechanism for reactive state updates. This simplifies the
architecture by eliminating manual subscription management and relying
on Zustand's automatic dependency tracking for component re-renders.

Key changes:
- Remove SubscriptionManager class from store.ts
- Replace all notifySubscribers calls with direct store updates
- Update hooks to use Zustand selectors with useShallow for complex data
- Remove subscribe/unsubscribe patterns from MessageManager
- Simplify EmbeddedChat to use selector instead of local state
- Rename requestConversationListRefresh to refreshConversations
This commit is contained in:
lafay
2026-03-31 19:15:13 +08:00
parent 94c11062f0
commit 259de04f3e
14 changed files with 198 additions and 993 deletions

View File

@@ -12,7 +12,7 @@
* - useChatScreen.ts: 自定义Hook管理所有状态和逻辑
* - EmojiPanel.tsx: 表情面板组件
* - MorePanel.tsx: 更多功能面板组件
* - MentionPanel.tsx: @成员选择面板组件
* - MentionPanel.tsx: @成员选择 面板组件
* - LongPressMenu.tsx: 长按菜单组件
* - ChatHeader.tsx: 聊天头部组件
* - MessageBubble.tsx: 消息气泡组件
@@ -258,10 +258,7 @@ export const ChatScreen: React.FC = () => {
useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
// 刷新会话列表,确保已读状态正确显示
messageManager.requestConversationListRefresh('chat-before-remove', {
force: true,
allowDefer: false,
});
messageManager.refreshConversations(true, 'chat-before-remove');
});
return unsubscribe;
}, [navigation]);

View File

@@ -22,7 +22,7 @@ import { Image as ExpoImage } from 'expo-image';
import { spacing, fontSizes, shadows, useAppColors, type AppColors } from '../../../theme';
import { ConversationResponse, MessageResponse, MessageSegment, GroupMemberResponse, ImageSegmentData } from '../../../types/dto';
import { Avatar, Text, ImageGallery, AppBackButton } from '../../../components/common';
import { useAuthStore, messageManager, MessageEvent, MessageSubscriber } from '../../../stores';
import { useAuthStore, messageManager, useMessageStore } from '../../../stores';
import { formatDistanceToNow } from 'date-fns';
import { zhCN } from 'date-fns/locale';
import { extractTextFromSegments } from '../../../types/dto';
@@ -302,8 +302,8 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
// 使用 markAsRead hook
const { markAsRead } = useMarkAsRead(String(conversation.id));
// 状态
const [messages, setMessages] = useState<MessageResponse[]>([]);
// 状态 - 使用 Zustand selector 直接订阅消息
const messages = useMessageStore(state => state.messagesMap.get(String(conversation.id)) || []);
const [loading, setLoading] = useState(true);
const [sending, setSending] = useState(false);
const [inputText, setInputText] = useState('');
@@ -490,7 +490,6 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
try {
setLoading(true);
await messageManager.fetchMessages(String(conversation.id));
setMessages(messageManager.getMessages(String(conversation.id)));
} catch (error: any) {
// 检查是否是权限错误或会话不存在错误
const errorMessage = error?.message || String(error);
@@ -501,8 +500,6 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
error?.code === 'FORBIDDEN'
) {
console.warn('[EmbeddedChat] 会话不存在或无权限访问:', conversation.id);
// 设置空消息列表,让 UI 显示"暂无消息"而不是崩溃
setMessages([]);
} else {
console.error('[EmbeddedChat] 加载消息失败:', error);
}
@@ -514,25 +511,6 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
// 初始加载
useEffect(() => {
loadMessages();
// 订阅消息事件
const subscriber: MessageSubscriber = (event: MessageEvent) => {
if (
event.type === 'messages_updated' &&
String(event.payload?.conversationId) === String(conversation.id)
) {
setMessages(event.payload.messages || []);
setTimeout(() => {
flatListRef.current?.scrollToEnd({ animated: true });
}, 100);
}
};
const unsubscribe = messageManager.subscribe(subscriber);
return () => {
unsubscribe();
};
}, [conversation.id, loadMessages]);
// 自动标记已读 - 当有新消息时