diff --git a/src/hooks/useDataService.ts b/src/hooks/useDataService.ts index 866b281..8e677ef 100644 --- a/src/hooks/useDataService.ts +++ b/src/hooks/useDataService.ts @@ -1,5 +1,4 @@ - -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { dataService } from '@/services/dataService'; import { IndJob } from '@/lib/types'; @@ -8,43 +7,75 @@ export function useJobs() { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + // Load jobs only once when the hook mounts useEffect(() => { + let mounted = true; + const loadJobs = async () => { try { setLoading(true); - await dataService.loadJobs(); - setError(null); + const loadedJobs = await dataService.loadJobs(); + if (mounted) { + setJobs(loadedJobs); + setError(null); + } } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to load jobs'); + if (mounted) { + setError(err instanceof Error ? err.message : 'Failed to load jobs'); + } } finally { - setLoading(false); + if (mounted) { + setLoading(false); + } } }; + // Start loading immediately loadJobs(); + // Set up subscription for updates const unsubscribe = dataService.subscribe(() => { - setJobs(dataService.getJobs()); + if (mounted) { + const currentJobs = dataService.getJobs(); + setJobs(prevJobs => { + // Only update if the jobs have actually changed + const prevJson = JSON.stringify(prevJobs); + const currentJson = JSON.stringify(currentJobs); + return prevJson !== currentJson ? currentJobs : prevJobs; + }); + } }); return () => { + mounted = false; unsubscribe(); }; - }, []); + }, []); // Empty dependency array ensures this only runs once on mount + + // Memoize the methods to prevent unnecessary re-renders + const createJob = useCallback(dataService.createJob.bind(dataService), []); + const updateJob = useCallback(dataService.updateJob.bind(dataService), []); + const deleteJob = useCallback(dataService.deleteJob.bind(dataService), []); + const createTransaction = useCallback(dataService.createTransaction.bind(dataService), []); + const createMultipleTransactions = useCallback(dataService.createMultipleTransactions.bind(dataService), []); + const updateTransaction = useCallback(dataService.updateTransaction.bind(dataService), []); + const deleteTransaction = useCallback(dataService.deleteTransaction.bind(dataService), []); + const createBillItem = useCallback(dataService.createBillItem.bind(dataService), []); + const createMultipleBillItems = useCallback(dataService.createMultipleBillItems.bind(dataService), []); return { jobs, loading, error, - createJob: dataService.createJob.bind(dataService), - updateJob: dataService.updateJob.bind(dataService), - deleteJob: dataService.deleteJob.bind(dataService), - createTransaction: dataService.createTransaction.bind(dataService), - createMultipleTransactions: dataService.createMultipleTransactions.bind(dataService), - updateTransaction: dataService.updateTransaction.bind(dataService), - deleteTransaction: dataService.deleteTransaction.bind(dataService), - createBillItem: dataService.createBillItem.bind(dataService), - createMultipleBillItems: dataService.createMultipleBillItems.bind(dataService) + createJob, + updateJob, + deleteJob, + createTransaction, + createMultipleTransactions, + updateTransaction, + deleteTransaction, + createBillItem, + createMultipleBillItems }; } diff --git a/src/services/dataService.ts b/src/services/dataService.ts index dd0e3fe..8246481 100644 --- a/src/services/dataService.ts +++ b/src/services/dataService.ts @@ -8,6 +8,7 @@ export class DataService { private static instance: DataService; private jobs: IndJob[] = []; private listeners: Set<() => void> = new Set(); + private loadPromise: Promise | null = null; private constructor() { } @@ -36,10 +37,27 @@ export class DataService { } async loadJobs(): Promise { + // If there's already a load in progress, return that promise + if (this.loadPromise) { + return this.loadPromise; + } + + // If we already have jobs loaded, return them immediately + if (this.jobs.length > 0) { + return Promise.resolve(this.getJobs()); + } + + // Start a new load console.log('Loading jobs from database'); - this.jobs = await jobService.getJobs(); - this.notifyListeners(); - return this.getJobs(); + this.loadPromise = jobService.getJobs().then(jobs => { + this.jobs = jobs; + this.notifyListeners(); + return this.getJobs(); + }).finally(() => { + this.loadPromise = null; + }); + + return this.loadPromise; } async createJob(jobData: IndJobRecordNoId): Promise {