211 lines
5.9 KiB
TypeScript
211 lines
5.9 KiB
TypeScript
/**
|
|
* Store Selectors
|
|
* FE-STATE-008: Optimize state selectors to prevent unnecessary re-renders
|
|
*
|
|
* Provides optimized selectors for Zustand stores to prevent unnecessary re-renders.
|
|
* Use these selectors instead of accessing the entire store.
|
|
*/
|
|
|
|
import { useShallow } from 'zustand/react/shallow';
|
|
import { useAuthStore } from '@/features/auth/store/authStore';
|
|
import { useUIStore } from '@/stores/ui';
|
|
import { useLibraryStore } from '@/stores/library';
|
|
import { useChatStore } from '@/stores/chat';
|
|
import { denormalize } from '@/utils/stateNormalization';
|
|
|
|
/**
|
|
* FE-STATE-008: Optimized selectors for AuthStore
|
|
*
|
|
* These hooks only re-render when the selected values actually change.
|
|
*/
|
|
export function useAuthUser() {
|
|
return useAuthStore(useShallow((state) => state.user));
|
|
}
|
|
|
|
export function useAuthStatus() {
|
|
return useAuthStore(useShallow((state) => ({
|
|
isAuthenticated: state.isAuthenticated,
|
|
isLoading: state.isLoading,
|
|
error: state.error,
|
|
})));
|
|
}
|
|
|
|
export function useAuthActions() {
|
|
return useAuthStore(useShallow((state) => ({
|
|
login: state.login,
|
|
register: state.register,
|
|
logout: state.logout,
|
|
refreshUser: state.refreshUser,
|
|
checkAuthStatus: state.checkAuthStatus,
|
|
clearError: state.clearError,
|
|
setLoading: state.setLoading,
|
|
})));
|
|
}
|
|
|
|
/**
|
|
* FE-STATE-008: Optimized selectors for UIStore
|
|
*/
|
|
export function useUITheme() {
|
|
return useUIStore(useShallow((state) => state.theme));
|
|
}
|
|
|
|
export function useUILanguage() {
|
|
return useUIStore(useShallow((state) => state.language));
|
|
}
|
|
|
|
export function useUISidebar() {
|
|
return useUIStore(useShallow((state) => ({
|
|
sidebarOpen: state.sidebarOpen,
|
|
setSidebarOpen: state.setSidebarOpen,
|
|
})));
|
|
}
|
|
|
|
export function useUINotifications() {
|
|
return useUIStore(useShallow((state) => ({
|
|
notifications: state.notifications,
|
|
addNotification: state.addNotification,
|
|
removeNotification: state.removeNotification,
|
|
markNotificationAsRead: state.markNotificationAsRead,
|
|
clearNotifications: state.clearNotifications,
|
|
})));
|
|
}
|
|
|
|
export function useUIActions() {
|
|
return useUIStore(useShallow((state) => ({
|
|
setTheme: state.setTheme,
|
|
setLanguage: state.setLanguage,
|
|
setSidebarOpen: state.setSidebarOpen,
|
|
})));
|
|
}
|
|
|
|
/**
|
|
* FE-STATE-008: Optimized selectors for LibraryStore
|
|
* FE-STATE-009: Convert normalized state to arrays for compatibility
|
|
*/
|
|
export function useLibraryItems() {
|
|
return useLibraryStore(useShallow((state) => denormalize(state.items)));
|
|
}
|
|
|
|
export function useLibraryFavorites() {
|
|
return useLibraryStore(useShallow((state) => denormalize(state.favorites)));
|
|
}
|
|
|
|
/**
|
|
* FE-STATE-009: Get normalized state directly (for advanced use cases)
|
|
*/
|
|
export function useLibraryItemsNormalized() {
|
|
return useLibraryStore(useShallow((state) => state.items));
|
|
}
|
|
|
|
export function useLibraryFavoritesNormalized() {
|
|
return useLibraryStore(useShallow((state) => state.favorites));
|
|
}
|
|
|
|
export function useLibraryFilters() {
|
|
return useLibraryStore(useShallow((state) => ({
|
|
filters: state.filters,
|
|
setFilters: state.setFilters,
|
|
})));
|
|
}
|
|
|
|
export function useLibraryPagination() {
|
|
return useLibraryStore(useShallow((state) => state.pagination));
|
|
}
|
|
|
|
export function useLibraryStatus() {
|
|
return useLibraryStore(useShallow((state) => ({
|
|
isLoading: state.isLoading,
|
|
error: state.error,
|
|
})));
|
|
}
|
|
|
|
export function useLibraryActions() {
|
|
return useLibraryStore(useShallow((state) => ({
|
|
fetchItems: state.fetchItems,
|
|
fetchFavorites: state.fetchFavorites,
|
|
uploadFile: state.uploadFile,
|
|
toggleFavorite: state.toggleFavorite,
|
|
deleteItem: state.deleteItem,
|
|
clearItems: state.clearItems,
|
|
})));
|
|
}
|
|
|
|
/**
|
|
* FE-STATE-008: Optimized selectors for ChatStore
|
|
*/
|
|
export function useChatConversations() {
|
|
return useChatStore(useShallow((state) => state.conversations));
|
|
}
|
|
|
|
export function useChatCurrentConversation() {
|
|
return useChatStore(useShallow((state) => state.currentConversation));
|
|
}
|
|
|
|
export function useChatMessages(conversationId: string) {
|
|
return useChatStore(useShallow((state) => state.messages[conversationId] || []));
|
|
}
|
|
|
|
export function useChatTypingUsers(conversationId: string) {
|
|
return useChatStore(useShallow((state) => state.typingUsers[conversationId] || []));
|
|
}
|
|
|
|
export function useChatConnection() {
|
|
return useChatStore(useShallow((state) => ({
|
|
isConnected: state.isConnected,
|
|
isLoading: state.isLoading,
|
|
error: state.error,
|
|
})));
|
|
}
|
|
|
|
export function useChatActions() {
|
|
return useChatStore(useShallow((state) => ({
|
|
setConversations: state.setConversations,
|
|
setCurrentConversation: state.setCurrentConversation,
|
|
addMessage: state.addMessage,
|
|
updateMessage: state.updateMessage,
|
|
removeMessage: state.removeMessage,
|
|
setMessages: state.setMessages,
|
|
setTypingUsers: state.setTypingUsers,
|
|
addTypingUser: state.addTypingUser,
|
|
removeTypingUser: state.removeTypingUser,
|
|
setConnected: state.setConnected,
|
|
setLoading: state.setLoading,
|
|
setError: state.setError,
|
|
connect: state.connect,
|
|
disconnect: state.disconnect,
|
|
joinConversation: state.joinConversation,
|
|
leaveConversation: state.leaveConversation,
|
|
sendMessage: state.sendMessage,
|
|
startTyping: state.startTyping,
|
|
stopTyping: state.stopTyping,
|
|
addReaction: state.addReaction,
|
|
removeReaction: state.removeReaction,
|
|
fetchConversations: state.fetchConversations,
|
|
createConversation: state.createConversation,
|
|
})));
|
|
}
|
|
|
|
/**
|
|
* FE-STATE-008: Helper function to create custom selectors
|
|
*
|
|
* Use this when you need to select multiple values from a store.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* // Instead of:
|
|
* const { user, isAuthenticated } = useAuthStore();
|
|
*
|
|
* // Use:
|
|
* const { user, isAuthenticated } = useStoreSelector(useAuthStore, (state) => ({
|
|
* user: state.user,
|
|
* isAuthenticated: state.isAuthenticated,
|
|
* }));
|
|
* ```
|
|
*/
|
|
export function useStoreSelector<T, U>(
|
|
store: (selector: (state: T) => U) => U,
|
|
selector: (state: T) => U,
|
|
): U {
|
|
return store(useShallow(selector));
|
|
}
|
|
|