UNPKG

fluid-pwa

Version:

🚀 The Ultimate Offline-First Progressive Web App Framework - Rapid PWA development with multiple batteries for seamless offline experiences

1 lines • 33.1 kB
{"version":3,"sources":["../src/lib/dexie/database.ts","../src/lib/dexie/hooks.ts","../src/lib/dexie/FluidPWAProvider.tsx"],"sourcesContent":["// Core database initialization for Fluid-PWA\r\nimport Dexie, { Table } from 'dexie'\r\nimport { v4 as uuidv4 } from 'uuid'\r\nimport { FluidPWAConfig, FluidDatabase, OfflineItem, SyncStatus } from './types'\r\n\r\n/**\r\n * Fluid-PWA Database class extending Dexie\r\n */\r\nexport class FluidPWADatabase extends Dexie {\r\n private config: FluidPWAConfig\r\n private isInitialized = false\r\n\r\n constructor(config: FluidPWAConfig) {\r\n super(config.databaseName)\r\n this.config = config\r\n this.setupDatabase()\r\n }\r\n\r\n private setupDatabase() {\r\n const version = this.config.version || 1\r\n \r\n // Set up the schema\r\n this.version(version).stores(this.config.schema)\r\n\r\n // Set up hooks for automatic field population\r\n this.setupHooks()\r\n\r\n // Mark as initialized\r\n this.isInitialized = true\r\n\r\n if (this.config.enableLogging) {\r\n console.log(`Fluid-PWA: Database \"${this.config.databaseName}\" initialized with schema:`, this.config.schema)\r\n }\r\n }\r\n\r\n private setupHooks() {\r\n // Hook into all tables to automatically set required fields\r\n Object.keys(this.config.schema).forEach(storeName => {\r\n const table = (this as any)[storeName] as Table<any, string>\r\n \r\n if (table) {\r\n // Before creating items, ensure required fields are set\r\n table.hook('creating', (primKey, obj, trans) => {\r\n this.populateOfflineFields(obj, 'NEW')\r\n })\r\n\r\n // Before updating items, update lastModifiedOffline\r\n table.hook('updating', (modifications: any, primKey, obj, trans) => {\r\n if (!modifications.lastModifiedOffline) {\r\n modifications.lastModifiedOffline = Date.now()\r\n }\r\n \r\n // Update sync status if not explicitly set\r\n if (!modifications.syncStatus && obj.syncStatus === 'SYNCED') {\r\n modifications.syncStatus = 'PENDING_UPDATE'\r\n }\r\n })\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * Populate required offline fields for new items\r\n */\r\n private populateOfflineFields(item: any, syncStatus: SyncStatus) {\r\n if (!item.localId) {\r\n item.localId = uuidv4()\r\n }\r\n \r\n if (!item.syncStatus) {\r\n item.syncStatus = syncStatus\r\n }\r\n \r\n if (!item.lastModifiedOffline) {\r\n item.lastModifiedOffline = Date.now()\r\n }\r\n \r\n if (this.config.userId && !item.userId) {\r\n item.userId = this.config.userId\r\n }\r\n }\r\n\r\n /**\r\n * Get all stores defined in the schema\r\n */\r\n getStoreNames(): string[] {\r\n return Object.keys(this.config.schema)\r\n }\r\n\r\n /**\r\n * Get a table by name with type safety\r\n */\r\n getTable<T = any>(storeName: string): Table<T & OfflineItem, string> {\r\n const table = (this as any)[storeName] as Table<T & OfflineItem, string>\r\n if (!table) {\r\n throw new Error(`Store \"${storeName}\" not found in database schema`)\r\n }\r\n return table\r\n }\r\n\r\n /**\r\n * Check if database is properly initialized\r\n */\r\n isReady(): boolean {\r\n return this.isInitialized && this.isOpen()\r\n }\r\n\r\n /**\r\n * Get configuration\r\n */\r\n getConfig(): FluidPWAConfig {\r\n return { ...this.config }\r\n }\r\n\r\n /**\r\n * Create a new item with proper offline fields\r\n */\r\n async createItem<T>(storeName: string, payload: Partial<T>, syncStatus: SyncStatus = 'PENDING_CREATE'): Promise<string> {\r\n const table = this.getTable<T>(storeName)\r\n const item = {\r\n ...payload,\r\n localId: uuidv4(),\r\n syncStatus,\r\n lastModifiedOffline: Date.now(),\r\n ...(this.config.userId && { userId: this.config.userId })\r\n }\r\n \r\n await table.add(item as any)\r\n return item.localId\r\n }\r\n\r\n /**\r\n * Update an item and mark for sync\r\n */\r\n async updateItem<T>(storeName: string, localId: string, updates: Partial<T>): Promise<number> {\r\n const table = this.getTable<T>(storeName)\r\n const item = await table.get(localId)\r\n \r\n if (!item) {\r\n throw new Error(`Item with localId \"${localId}\" not found in store \"${storeName}\"`)\r\n }\r\n\r\n const updateData: any = {\r\n ...updates,\r\n lastModifiedOffline: Date.now(),\r\n syncStatus: item.syncStatus === 'SYNCED' ? 'PENDING_UPDATE' as SyncStatus : item.syncStatus\r\n }\r\n\r\n return table.update(localId, updateData)\r\n }\r\n\r\n /**\r\n * Delete an item (soft delete with sync status)\r\n */\r\n async deleteItem(storeName: string, localId: string): Promise<void> {\r\n const table = this.getTable(storeName)\r\n const item = await table.get(localId)\r\n \r\n if (!item) {\r\n throw new Error(`Item with localId \"${localId}\" not found in store \"${storeName}\"`)\r\n }\r\n\r\n // If item was never synced, we can hard delete\r\n if (item.syncStatus === 'NEW' || item.syncStatus === 'PENDING_CREATE') {\r\n await table.delete(localId)\r\n } else {\r\n // Soft delete - mark for deletion sync\r\n await table.update(localId, {\r\n syncStatus: 'PENDING_DELETE' as SyncStatus,\r\n lastModifiedOffline: Date.now()\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Get items by sync status\r\n */\r\n async getItemsBySyncStatus(storeName: string, syncStatus: SyncStatus | SyncStatus[]): Promise<any[]> {\r\n const table = this.getTable(storeName)\r\n const statuses = Array.isArray(syncStatus) ? syncStatus : [syncStatus]\r\n \r\n return table.where('syncStatus').anyOf(statuses).toArray()\r\n }\r\n\r\n /**\r\n * Get all pending items across all stores (for sync queue)\r\n */\r\n async getAllPendingItems(): Promise<any[]> {\r\n const pendingStatuses: SyncStatus[] = ['PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE']\r\n const allPending: any[] = []\r\n \r\n for (const storeName of this.getStoreNames()) {\r\n const items = await this.getItemsBySyncStatus(storeName, pendingStatuses)\r\n items.forEach(item => {\r\n allPending.push({\r\n ...item,\r\n storeName\r\n })\r\n })\r\n }\r\n \r\n return allPending\r\n }\r\n}\r\n\r\n// Singleton instance\r\nlet dbInstance: FluidPWADatabase | null = null\r\n\r\n/**\r\n * Initialize the Fluid-PWA database\r\n */\r\nexport function initializeFluidPWA(config: FluidPWAConfig): FluidPWADatabase {\r\n if (dbInstance) {\r\n console.warn('Fluid-PWA: Database already initialized. Returning existing instance.')\r\n return dbInstance\r\n }\r\n\r\n dbInstance = new FluidPWADatabase(config)\r\n return dbInstance\r\n}\r\n\r\n/**\r\n * Get the current database instance\r\n */\r\nexport function getFluidPWADatabase(): FluidPWADatabase {\r\n if (!dbInstance) {\r\n throw new Error('Fluid-PWA: Database not initialized. Call initializeFluidPWA() first.')\r\n }\r\n return dbInstance\r\n}\r\n\r\n/**\r\n * Check if database is initialized\r\n */\r\nexport function isFluidPWAInitialized(): boolean {\r\n return dbInstance !== null && dbInstance.isReady()\r\n} ","// React hooks for Fluid-PWA CRUD operations\r\n'use client'\r\n\r\nimport { useState, useEffect, useCallback } from 'react'\r\nimport { useLiveQuery } from 'dexie-react-hooks'\r\nimport { getFluidPWADatabase } from './database'\r\nimport { CRUDOptions, CRUDResult, QueryOptions, SyncStatus, OfflineItem } from './types'\r\n\r\n/**\r\n * Hook to add items to a store\r\n */\r\nexport function useAddItem<T = any>(\r\n storeName: string, \r\n options: CRUDOptions = {}\r\n): (payload: Partial<T>, syncStatus?: SyncStatus) => Promise<CRUDResult<string>> {\r\n const db = getFluidPWADatabase()\r\n\r\n return useCallback(async (payload: Partial<T>, syncStatus: SyncStatus = 'PENDING_CREATE'): Promise<CRUDResult<string>> => {\r\n try {\r\n // Call before hook if provided\r\n let processedPayload = payload\r\n if (options.onBeforeAdd) {\r\n processedPayload = await options.onBeforeAdd(payload)\r\n }\r\n\r\n const localId = await db.createItem<T>(storeName, processedPayload, syncStatus)\r\n\r\n // Call after hook if provided\r\n if (options.onAfterAdd) {\r\n await options.onAfterAdd(processedPayload, localId)\r\n }\r\n\r\n return { success: true, data: localId }\r\n } catch (error) {\r\n return { \r\n success: false, \r\n error: error instanceof Error ? error.message : 'Unknown error occurred' \r\n }\r\n }\r\n }, [db, storeName, options])\r\n}\r\n\r\n/**\r\n * Hook to get a single item by localId\r\n */\r\nexport function useGetItem<T = any>(\r\n storeName: string, \r\n localId?: string\r\n): T & OfflineItem | undefined {\r\n return useLiveQuery(\r\n async () => {\r\n if (!localId) return undefined\r\n const db = getFluidPWADatabase()\r\n const table = db.getTable<T>(storeName)\r\n return table.get(localId)\r\n },\r\n [storeName, localId]\r\n )\r\n}\r\n\r\n/**\r\n * Hook to get all items from a store with optional filtering\r\n */\r\nexport function useGetAllItems<T = any>(\r\n storeName: string,\r\n queryOptions: QueryOptions = {}\r\n): (T & OfflineItem)[] | undefined {\r\n return useLiveQuery(\r\n async () => {\r\n const db = getFluidPWADatabase()\r\n const table = db.getTable<T>(storeName)\r\n let query = table.toCollection()\r\n\r\n // Apply ordering\r\n if (queryOptions.orderBy) {\r\n query = table.orderBy(queryOptions.orderBy)\r\n if (queryOptions.reverse) {\r\n query = query.reverse()\r\n }\r\n }\r\n\r\n // Apply offset and limit\r\n if (queryOptions.offset) {\r\n query = query.offset(queryOptions.offset)\r\n }\r\n if (queryOptions.limit) {\r\n query = query.limit(queryOptions.limit)\r\n }\r\n\r\n let results = await query.toArray()\r\n\r\n // Apply filter if provided\r\n if (queryOptions.filter) {\r\n results = results.filter(queryOptions.filter)\r\n }\r\n\r\n return results\r\n },\r\n [storeName, queryOptions.orderBy, queryOptions.reverse, queryOptions.offset, queryOptions.limit]\r\n )\r\n}\r\n\r\n/**\r\n * Hook to update items\r\n */\r\nexport function useUpdateItem<T = any>(\r\n storeName: string,\r\n options: CRUDOptions = {}\r\n): (localId: string, updates: Partial<T>) => Promise<CRUDResult<number>> {\r\n const db = getFluidPWADatabase()\r\n\r\n return useCallback(async (localId: string, updates: Partial<T>): Promise<CRUDResult<number>> => {\r\n try {\r\n // Call before hook if provided\r\n let processedUpdates = updates\r\n if (options.onBeforeUpdate) {\r\n const existingItem = await db.getTable<T>(storeName).get(localId)\r\n processedUpdates = await options.onBeforeUpdate(existingItem, updates)\r\n }\r\n\r\n const result = await db.updateItem<T>(storeName, localId, processedUpdates)\r\n\r\n // Call after hook if provided\r\n if (options.onAfterUpdate) {\r\n const updatedItem = await db.getTable<T>(storeName).get(localId)\r\n await options.onAfterUpdate(updatedItem, result)\r\n }\r\n\r\n return { success: true, data: result }\r\n } catch (error) {\r\n return { \r\n success: false, \r\n error: error instanceof Error ? error.message : 'Unknown error occurred' \r\n }\r\n }\r\n }, [db, storeName, options])\r\n}\r\n\r\n/**\r\n * Hook to delete items\r\n */\r\nexport function useDeleteItem(\r\n storeName: string,\r\n options: CRUDOptions = {}\r\n): (localId: string) => Promise<CRUDResult<void>> {\r\n const db = getFluidPWADatabase()\r\n\r\n return useCallback(async (localId: string): Promise<CRUDResult<void>> => {\r\n try {\r\n // Call before hook if provided\r\n if (options.onBeforeDelete) {\r\n const shouldDelete = await options.onBeforeDelete(localId)\r\n if (!shouldDelete) {\r\n return { success: false, error: 'Delete operation cancelled by before hook' }\r\n }\r\n }\r\n\r\n await db.deleteItem(storeName, localId)\r\n\r\n // Call after hook if provided\r\n if (options.onAfterDelete) {\r\n await options.onAfterDelete(localId)\r\n }\r\n\r\n return { success: true }\r\n } catch (error) {\r\n return { \r\n success: false, \r\n error: error instanceof Error ? error.message : 'Unknown error occurred' \r\n }\r\n }\r\n }, [db, storeName, options])\r\n}\r\n\r\n/**\r\n * Hook to get items by sync status\r\n */\r\nexport function useGetItemsBySyncStatus<T = any>(\r\n storeName: string,\r\n syncStatus: SyncStatus | SyncStatus[]\r\n): (T & OfflineItem)[] | undefined {\r\n return useLiveQuery(\r\n async () => {\r\n const db = getFluidPWADatabase()\r\n return db.getItemsBySyncStatus(storeName, syncStatus)\r\n },\r\n [storeName, syncStatus]\r\n )\r\n}\r\n\r\n/**\r\n * Hook to get pending items (items that need to be synced)\r\n */\r\nexport function useGetPendingItems<T = any>(\r\n storeName: string\r\n): (T & OfflineItem)[] | undefined {\r\n const pendingStatuses: SyncStatus[] = ['PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE']\r\n return useGetItemsBySyncStatus<T>(storeName, pendingStatuses)\r\n}\r\n\r\n/**\r\n * Hook to get all pending items across all stores\r\n */\r\nexport function useGetAllPendingItems(): any[] | undefined {\r\n return useLiveQuery(\r\n async () => {\r\n const db = getFluidPWADatabase()\r\n return db.getAllPendingItems()\r\n },\r\n []\r\n )\r\n}\r\n\r\n/**\r\n * Hook to get database statistics\r\n */\r\nexport function useFluidPWAStats() {\r\n return useLiveQuery(\r\n async () => {\r\n const db = getFluidPWADatabase()\r\n const stats: Record<string, any> = {}\r\n \r\n for (const storeName of db.getStoreNames()) {\r\n const table = db.getTable(storeName)\r\n const total = await table.count()\r\n const pending = await db.getItemsBySyncStatus(storeName, ['PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE'])\r\n const synced = await db.getItemsBySyncStatus(storeName, 'SYNCED')\r\n const errors = await db.getItemsBySyncStatus(storeName, 'ERROR')\r\n \r\n stats[storeName] = {\r\n total,\r\n pending: pending.length,\r\n synced: synced.length,\r\n errors: errors.length\r\n }\r\n }\r\n \r\n return stats\r\n },\r\n []\r\n )\r\n}\r\n\r\n/**\r\n * Hook for bulk operations\r\n */\r\nexport function useBulkOperations(storeName: string) {\r\n const db = getFluidPWADatabase()\r\n\r\n const bulkAdd = useCallback(async <T>(items: (Partial<T> & { localId?: string })[]): Promise<CRUDResult<string[]>> => {\r\n try {\r\n const table = db.getTable<T>(storeName)\r\n const processedItems = items.map(item => ({\r\n ...item,\r\n localId: item.localId || crypto.randomUUID(),\r\n syncStatus: 'PENDING_CREATE' as SyncStatus,\r\n lastModifiedOffline: Date.now(),\r\n ...(db.getConfig().userId && { userId: db.getConfig().userId })\r\n }))\r\n\r\n await table.bulkAdd(processedItems as any)\r\n return { \r\n success: true, \r\n data: processedItems.map(item => item.localId!) \r\n }\r\n } catch (error) {\r\n return { \r\n success: false, \r\n error: error instanceof Error ? error.message : 'Bulk add failed' \r\n }\r\n }\r\n }, [db, storeName])\r\n\r\n const bulkUpdate = useCallback(async <T>(updates: { localId: string; changes: Partial<T> }[]): Promise<CRUDResult<number>> => {\r\n try {\r\n const table = db.getTable<T>(storeName)\r\n let totalUpdated = 0\r\n\r\n for (const { localId, changes } of updates) {\r\n const updated = await db.updateItem<T>(storeName, localId, changes)\r\n totalUpdated += updated\r\n }\r\n\r\n return { success: true, data: totalUpdated }\r\n } catch (error) {\r\n return { \r\n success: false, \r\n error: error instanceof Error ? error.message : 'Bulk update failed' \r\n }\r\n }\r\n }, [db, storeName])\r\n\r\n const bulkDelete = useCallback(async (localIds: string[]): Promise<CRUDResult<number>> => {\r\n try {\r\n let totalDeleted = 0\r\n\r\n for (const localId of localIds) {\r\n await db.deleteItem(storeName, localId)\r\n totalDeleted++\r\n }\r\n\r\n return { success: true, data: totalDeleted }\r\n } catch (error) {\r\n return { \r\n success: false, \r\n error: error instanceof Error ? error.message : 'Bulk delete failed' \r\n }\r\n }\r\n }, [db, storeName])\r\n\r\n return {\r\n bulkAdd,\r\n bulkUpdate,\r\n bulkDelete\r\n }\r\n} ","// React Provider for Fluid-PWA\r\n'use client'\r\n\r\nimport React, { createContext, useContext, useEffect, useState, ReactNode } from 'react'\r\nimport { FluidPWAConfig } from './types'\r\nimport { FluidPWADatabase, initializeFluidPWA, getFluidPWADatabase, isFluidPWAInitialized } from './database'\r\n\r\ninterface FluidPWAContextType {\r\n database: FluidPWADatabase | null\r\n isInitialized: boolean\r\n isLoading: boolean\r\n error: string | null\r\n config: FluidPWAConfig | null\r\n}\r\n\r\nconst FluidPWAContext = createContext<FluidPWAContextType>({\r\n database: null,\r\n isInitialized: false,\r\n isLoading: true,\r\n error: null,\r\n config: null\r\n})\r\n\r\ninterface FluidPWAProviderProps {\r\n children: ReactNode\r\n config: FluidPWAConfig\r\n onInitialized?: (database: FluidPWADatabase) => void\r\n onError?: (error: Error) => void\r\n}\r\n\r\n/**\r\n * Provider component for Fluid-PWA that initializes the database\r\n * and provides it to child components via context\r\n */\r\nexport function FluidPWAProvider({ \r\n children, \r\n config, \r\n onInitialized,\r\n onError \r\n}: FluidPWAProviderProps) {\r\n const [database, setDatabase] = useState<FluidPWADatabase | null>(null)\r\n const [isLoading, setIsLoading] = useState(true)\r\n const [error, setError] = useState<string | null>(null)\r\n\r\n useEffect(() => {\r\n const initDatabase = async () => {\r\n try {\r\n setIsLoading(true)\r\n setError(null)\r\n\r\n let db: FluidPWADatabase\r\n\r\n if (isFluidPWAInitialized()) {\r\n // Use existing instance\r\n db = getFluidPWADatabase()\r\n if (config.enableLogging) {\r\n console.log('Fluid-PWA: Using existing database instance')\r\n }\r\n } else {\r\n // Initialize new instance\r\n if (config.enableLogging) {\r\n console.log('Fluid-PWA: Initializing database with config:', config)\r\n }\r\n db = initializeFluidPWA(config)\r\n }\r\n\r\n // Wait for database to be ready\r\n await db.open()\r\n \r\n setDatabase(db)\r\n onInitialized?.(db)\r\n\r\n if (config.enableLogging) {\r\n console.log('Fluid-PWA: Database successfully initialized and ready')\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to initialize Fluid-PWA database'\r\n setError(errorMessage)\r\n onError?.(err instanceof Error ? err : new Error(errorMessage))\r\n \r\n if (config.enableLogging) {\r\n console.error('Fluid-PWA: Database initialization failed:', err)\r\n }\r\n } finally {\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n initDatabase()\r\n }, [config, onInitialized, onError])\r\n\r\n const contextValue: FluidPWAContextType = {\r\n database,\r\n isInitialized: database !== null && database.isReady(),\r\n isLoading,\r\n error,\r\n config\r\n }\r\n\r\n return (\r\n <FluidPWAContext.Provider value={contextValue}>\r\n {children}\r\n </FluidPWAContext.Provider>\r\n )\r\n}\r\n\r\n/**\r\n * Hook to access the Fluid-PWA context\r\n */\r\nexport function useFluidPWA(): FluidPWAContextType {\r\n const context = useContext(FluidPWAContext)\r\n \r\n if (!context) {\r\n throw new Error('useFluidPWA must be used within a FluidPWAProvider')\r\n }\r\n \r\n return context\r\n}\r\n\r\n/**\r\n * Hook to get the database instance with error handling\r\n */\r\nexport function useFluidPWADatabase(): FluidPWADatabase {\r\n const { database, isInitialized, error } = useFluidPWA()\r\n \r\n if (error) {\r\n throw new Error(`Fluid-PWA Error: ${error}`)\r\n }\r\n \r\n if (!isInitialized || !database) {\r\n throw new Error('Fluid-PWA: Database not yet initialized')\r\n }\r\n \r\n return database\r\n}\r\n\r\n/**\r\n * Higher-order component for wrapping pages/components with Fluid-PWA\r\n */\r\nexport function withFluidPWA<P extends object>(\r\n Component: React.ComponentType<P>,\r\n config: FluidPWAConfig\r\n) {\r\n return function WrappedComponent(props: P) {\r\n return (\r\n <FluidPWAProvider config={config}>\r\n <Component {...props} />\r\n </FluidPWAProvider>\r\n )\r\n }\r\n}\r\n\r\n/**\r\n * Component to display loading/error states for Fluid-PWA initialization\r\n */\r\ninterface FluidPWAStatusProps {\r\n children: ReactNode\r\n loadingComponent?: ReactNode\r\n errorComponent?: (error: string) => ReactNode\r\n}\r\n\r\nexport function FluidPWAStatus({ \r\n children, \r\n loadingComponent,\r\n errorComponent \r\n}: FluidPWAStatusProps) {\r\n const { isInitialized, isLoading, error } = useFluidPWA()\r\n\r\n if (error && errorComponent) {\r\n return <>{errorComponent(error)}</>\r\n }\r\n\r\n if (error) {\r\n return (\r\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-md\">\r\n <h3 className=\"text-red-800 font-medium\">Database Error</h3>\r\n <p className=\"text-red-600 text-sm mt-1\">{error}</p>\r\n </div>\r\n )\r\n }\r\n\r\n if (isLoading && loadingComponent) {\r\n return <>{loadingComponent}</>\r\n }\r\n\r\n if (isLoading) {\r\n return (\r\n <div className=\"flex items-center justify-center p-8\">\r\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\"></div>\r\n <span className=\"ml-3 text-gray-600\">Initializing offline database...</span>\r\n </div>\r\n )\r\n }\r\n\r\n if (!isInitialized) {\r\n return (\r\n <div className=\"p-4 bg-yellow-50 border border-yellow-200 rounded-md\">\r\n <p className=\"text-yellow-800\">Database not yet ready...</p>\r\n </div>\r\n )\r\n }\r\n\r\n return <>{children}</>\r\n} "],"mappings":"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","names":["useEffect","useState","useState","useEffect"]}