mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 15:51:12 -05:00
Fix realtime subscription loop
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState, useRef, useCallback } from 'react';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { RealtimeChannel } from '@supabase/supabase-js';
|
import { RealtimeChannel } from '@supabase/supabase-js';
|
||||||
|
|
||||||
@@ -22,9 +22,15 @@ export const useRealtimeModerationStats = (options: UseRealtimeModerationStatsOp
|
|||||||
flaggedContent: 0,
|
flaggedContent: 0,
|
||||||
});
|
});
|
||||||
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
|
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
|
||||||
const [updateTimer, setUpdateTimer] = useState<NodeJS.Timeout | null>(null);
|
const updateTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const onStatsChangeRef = useRef(onStatsChange);
|
||||||
|
|
||||||
const fetchStats = async () => {
|
// Update ref when callback changes
|
||||||
|
useEffect(() => {
|
||||||
|
onStatsChangeRef.current = onStatsChange;
|
||||||
|
}, [onStatsChange]);
|
||||||
|
|
||||||
|
const fetchStats = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const [submissionsResult, reportsResult, reviewsResult] = await Promise.all([
|
const [submissionsResult, reportsResult, reviewsResult] = await Promise.all([
|
||||||
supabase
|
supabase
|
||||||
@@ -48,19 +54,18 @@ export const useRealtimeModerationStats = (options: UseRealtimeModerationStatsOp
|
|||||||
};
|
};
|
||||||
|
|
||||||
setStats(newStats);
|
setStats(newStats);
|
||||||
onStatsChange?.(newStats);
|
onStatsChangeRef.current?.(newStats);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching moderation stats:', error);
|
console.error('Error fetching moderation stats:', error);
|
||||||
}
|
}
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const debouncedFetchStats = () => {
|
const debouncedFetchStats = useCallback(() => {
|
||||||
if (updateTimer) {
|
if (updateTimerRef.current) {
|
||||||
clearTimeout(updateTimer);
|
clearTimeout(updateTimerRef.current);
|
||||||
}
|
}
|
||||||
const timer = setTimeout(fetchStats, debounceMs);
|
updateTimerRef.current = setTimeout(fetchStats, debounceMs);
|
||||||
setUpdateTimer(timer);
|
}, [fetchStats, debounceMs]);
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
@@ -115,12 +120,12 @@ export const useRealtimeModerationStats = (options: UseRealtimeModerationStatsOp
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
console.log('Cleaning up moderation stats realtime subscription');
|
console.log('Cleaning up moderation stats realtime subscription');
|
||||||
if (updateTimer) {
|
if (updateTimerRef.current) {
|
||||||
clearTimeout(updateTimer);
|
clearTimeout(updateTimerRef.current);
|
||||||
}
|
}
|
||||||
supabase.removeChannel(realtimeChannel);
|
supabase.removeChannel(realtimeChannel);
|
||||||
};
|
};
|
||||||
}, [enabled]);
|
}, [enabled, fetchStats, debouncedFetchStats]);
|
||||||
|
|
||||||
return { stats, refresh: fetchStats };
|
return { stats, refresh: fetchStats };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { RealtimeChannel } from '@supabase/supabase-js';
|
import { RealtimeChannel } from '@supabase/supabase-js';
|
||||||
|
|
||||||
@@ -12,6 +12,14 @@ export const useRealtimeSubmissionItems = (options: UseRealtimeSubmissionItemsOp
|
|||||||
const { submissionId, onUpdate, enabled = true } = options;
|
const { submissionId, onUpdate, enabled = true } = options;
|
||||||
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
|
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
|
||||||
|
|
||||||
|
// Use ref to store latest callback without triggering re-subscriptions
|
||||||
|
const onUpdateRef = useRef(onUpdate);
|
||||||
|
|
||||||
|
// Update ref when callback changes
|
||||||
|
useEffect(() => {
|
||||||
|
onUpdateRef.current = onUpdate;
|
||||||
|
}, [onUpdate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enabled || !submissionId) return;
|
if (!enabled || !submissionId) return;
|
||||||
|
|
||||||
@@ -27,7 +35,7 @@ export const useRealtimeSubmissionItems = (options: UseRealtimeSubmissionItemsOp
|
|||||||
},
|
},
|
||||||
(payload) => {
|
(payload) => {
|
||||||
console.log('Submission item updated:', payload);
|
console.log('Submission item updated:', payload);
|
||||||
onUpdate?.(payload);
|
onUpdateRef.current?.(payload);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.subscribe((status) => {
|
.subscribe((status) => {
|
||||||
@@ -40,7 +48,7 @@ export const useRealtimeSubmissionItems = (options: UseRealtimeSubmissionItemsOp
|
|||||||
console.log('Cleaning up submission items realtime subscription');
|
console.log('Cleaning up submission items realtime subscription');
|
||||||
supabase.removeChannel(realtimeChannel);
|
supabase.removeChannel(realtimeChannel);
|
||||||
};
|
};
|
||||||
}, [submissionId, enabled, onUpdate]);
|
}, [submissionId, enabled]);
|
||||||
|
|
||||||
return { channel };
|
return { channel };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { RealtimeChannel } from '@supabase/supabase-js';
|
import { RealtimeChannel } from '@supabase/supabase-js';
|
||||||
|
|
||||||
@@ -13,6 +13,18 @@ export const useRealtimeSubmissions = (options: UseRealtimeSubmissionsOptions =
|
|||||||
const { onInsert, onUpdate, onDelete, enabled = true } = options;
|
const { onInsert, onUpdate, onDelete, enabled = true } = options;
|
||||||
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
|
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
|
||||||
|
|
||||||
|
// Use refs to store latest callbacks without triggering re-subscriptions
|
||||||
|
const onInsertRef = useRef(onInsert);
|
||||||
|
const onUpdateRef = useRef(onUpdate);
|
||||||
|
const onDeleteRef = useRef(onDelete);
|
||||||
|
|
||||||
|
// Update refs when callbacks change
|
||||||
|
useEffect(() => {
|
||||||
|
onInsertRef.current = onInsert;
|
||||||
|
onUpdateRef.current = onUpdate;
|
||||||
|
onDeleteRef.current = onDelete;
|
||||||
|
}, [onInsert, onUpdate, onDelete]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
|
|
||||||
@@ -27,7 +39,7 @@ export const useRealtimeSubmissions = (options: UseRealtimeSubmissionsOptions =
|
|||||||
},
|
},
|
||||||
(payload) => {
|
(payload) => {
|
||||||
console.log('Submission inserted:', payload);
|
console.log('Submission inserted:', payload);
|
||||||
onInsert?.(payload);
|
onInsertRef.current?.(payload);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.on(
|
.on(
|
||||||
@@ -39,7 +51,7 @@ export const useRealtimeSubmissions = (options: UseRealtimeSubmissionsOptions =
|
|||||||
},
|
},
|
||||||
(payload) => {
|
(payload) => {
|
||||||
console.log('Submission updated:', payload);
|
console.log('Submission updated:', payload);
|
||||||
onUpdate?.(payload);
|
onUpdateRef.current?.(payload);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.on(
|
.on(
|
||||||
@@ -51,7 +63,7 @@ export const useRealtimeSubmissions = (options: UseRealtimeSubmissionsOptions =
|
|||||||
},
|
},
|
||||||
(payload) => {
|
(payload) => {
|
||||||
console.log('Submission deleted:', payload);
|
console.log('Submission deleted:', payload);
|
||||||
onDelete?.(payload);
|
onDeleteRef.current?.(payload);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.subscribe((status) => {
|
.subscribe((status) => {
|
||||||
@@ -64,7 +76,7 @@ export const useRealtimeSubmissions = (options: UseRealtimeSubmissionsOptions =
|
|||||||
console.log('Cleaning up submissions realtime subscription');
|
console.log('Cleaning up submissions realtime subscription');
|
||||||
supabase.removeChannel(realtimeChannel);
|
supabase.removeChannel(realtimeChannel);
|
||||||
};
|
};
|
||||||
}, [enabled, onInsert, onUpdate, onDelete]);
|
}, [enabled]);
|
||||||
|
|
||||||
return { channel };
|
return { channel };
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user