refactor(core): optimize state management and component rendering performance
Improve application stability and performance by optimizing Zustand store usage, implementing memoization patterns, and introducing persistent authentication. - **State Management**: - Refactor Zustand selectors to use `useShallow` and `getState()` to prevent unnecessary re-renders and infinite loops in hooks. - Implement `persist` middleware for `authStore` to maintain user sessions across restarts. - Introduce `buildStateCached` in `themeStore` to reduce redundant theme object computations. - **Performance & Rendering**: - Implement `useMemo` for stable object/array references in `ImageGallery` and list components to prevent expensive re-renders. - Replace inline arrow functions with `useCallback` in complex screens like `ChatScreen` and `MessageListScreen`. - Optimize `FlashList` usage by providing stable `key` and `extraData` props. - **Architecture**: - Decouple unread count fetching by introducing `useUnreadCountQuery` (React Query) for better caching and synchronization. - Add `useChannels` hook to centralize channel data fetching. - Refine `SessionGate` logic to allow immediate rendering of authenticated users while verifying in the background.
This commit is contained in:
@@ -97,13 +97,14 @@ export function useMessages(
|
||||
loadMoreMessages: (conversationId: string, beforeSeq: number, limit?: number) => Promise<MessageResponse[]>
|
||||
): UseMessagesReturn {
|
||||
const normalizedConversationId = normalizeConversationId(conversationId);
|
||||
const store = useMessageStore();
|
||||
|
||||
|
||||
// 使用 useShallow 避免每次返回新数组引用导致的无限循环
|
||||
const messages = useMessageStore(
|
||||
useShallow(state => state.messagesMap.get(normalizedConversationId) || [])
|
||||
);
|
||||
const isLoadingMessages = useMessageStore(state => state.loadingMessagesSet.has(normalizedConversationId));
|
||||
const getActiveConversation = useMessageStore.getState().getActiveConversation;
|
||||
const setCurrentConversation = useMessageStore.getState().setCurrentConversation;
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -114,8 +115,8 @@ export function useMessages(
|
||||
|
||||
return () => {
|
||||
// 清理活动会话
|
||||
if (store.getActiveConversation() === normalizedConversationId) {
|
||||
store.setCurrentConversation(null);
|
||||
if (getActiveConversation() === normalizedConversationId) {
|
||||
setCurrentConversation(null);
|
||||
}
|
||||
};
|
||||
}, [normalizedConversationId]);
|
||||
@@ -428,11 +429,10 @@ interface UseGroupMutedReturn {
|
||||
export function useGroupMuted(groupId: string): UseGroupMutedReturn {
|
||||
// 使用 Zustand selector 直接订阅禁言状态
|
||||
const isMuted = useMessageStore(state => state.mutedStatusMap.get(groupId) || false);
|
||||
const store = useMessageStore();
|
||||
|
||||
const setMutedStatus = useCallback((muted: boolean) => {
|
||||
store.setMutedStatus(groupId, muted);
|
||||
}, [groupId, store]);
|
||||
useMessageStore.getState().setMutedStatus(groupId, muted);
|
||||
}, [groupId]);
|
||||
|
||||
return {
|
||||
isMuted,
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useShallow } from 'zustand/react/shallow';
|
||||
import { ConversationResponse, MessageResponse, MessageSegment } from '../../types/dto';
|
||||
import { messageManager } from './MessageManager';
|
||||
import { useMessageStore } from './store';
|
||||
import { useUnreadCountQuery } from '../../hooks/useUnreadCount';
|
||||
|
||||
// ==================== useConversations - 获取会话列表 ====================
|
||||
|
||||
@@ -43,16 +44,19 @@ export function useConversations(): UseConversationsReturn {
|
||||
console.error('[useConversations] 初始化失败:', error);
|
||||
});
|
||||
|
||||
// 冷启动兜底:延迟做一次强制刷新,避免首次因时序问题拿到空列表
|
||||
const coldStartSyncTimer = setTimeout(() => {
|
||||
messageManager.refreshConversations(true, 'hooks-initial-refresh').catch(error => {
|
||||
console.error('[useConversations] 冷启动强制刷新失败:', error);
|
||||
});
|
||||
}, 1200);
|
||||
// 仅在首次初始化时做一次冷启动兜底刷新,避免每次挂载都触发
|
||||
const store = useMessageStore.getState();
|
||||
if (!store.isInitialized) {
|
||||
const coldStartSyncTimer = setTimeout(() => {
|
||||
messageManager.refreshConversations(true, 'hooks-initial-refresh').catch(error => {
|
||||
console.error('[useConversations] 冷启动强制刷新失败:', error);
|
||||
});
|
||||
}, 1200);
|
||||
|
||||
return () => {
|
||||
clearTimeout(coldStartSyncTimer);
|
||||
};
|
||||
return () => {
|
||||
clearTimeout(coldStartSyncTimer);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 监听 hasMore 变化
|
||||
@@ -249,15 +253,11 @@ interface UseUnreadCountReturn {
|
||||
* 使用 Zustand selector 直接订阅未读数变化
|
||||
*/
|
||||
export function useUnreadCount(): UseUnreadCountReturn {
|
||||
// 使用 Zustand selector 直接订阅未读数
|
||||
// Use React Query for fetching (caching + auto-refetch), Zustand selectors for reading
|
||||
useUnreadCountQuery();
|
||||
const totalUnreadCount = useMessageStore(state => state.totalUnreadCount);
|
||||
const systemUnreadCount = useMessageStore(state => state.systemUnreadCount);
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化时获取最新未读数
|
||||
messageManager.fetchUnreadCount();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
totalUnreadCount,
|
||||
systemUnreadCount,
|
||||
@@ -271,14 +271,11 @@ export function useUnreadCount(): UseUnreadCountReturn {
|
||||
* 使用 Zustand selector 直接订阅
|
||||
*/
|
||||
export function useTotalUnreadCount(): number {
|
||||
// Use React Query for fetching, Zustand selectors for reading
|
||||
useUnreadCountQuery();
|
||||
const totalUnreadCount = useMessageStore(state => state.totalUnreadCount);
|
||||
const systemUnreadCount = useMessageStore(state => state.systemUnreadCount);
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化时获取最新未读数
|
||||
messageManager.fetchUnreadCount();
|
||||
}, []);
|
||||
|
||||
return totalUnreadCount + systemUnreadCount;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user