fix: clear setTimeout ref on unmount, stable roadmapIdKey dep for votes effect
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { PortableTextRenderer } from '@/components/PortableTextRenderer'
|
import { PortableTextRenderer } from '@/components/PortableTextRenderer'
|
||||||
import { RoadmapItem } from '@/components/RoadmapItem'
|
import { RoadmapItem } from '@/components/RoadmapItem'
|
||||||
import type { ChangelogEntry, RoadmapItemData, Tab, VoteState } from '@/types/changelog'
|
import type { ChangelogEntry, RoadmapItemData, Tab, VoteState } from '@/types/changelog'
|
||||||
@@ -48,15 +48,21 @@ export function ChangelogTabs({
|
|||||||
|
|
||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
const [showSignInPrompt, setShowSignInPrompt] = useState(false)
|
const [showSignInPrompt, setShowSignInPrompt] = useState(false)
|
||||||
|
const signInTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
const [votesFetched, setVotesFetched] = useState(false)
|
const [votesFetched, setVotesFetched] = useState(false)
|
||||||
|
|
||||||
|
// Clear sign-in prompt timer on unmount
|
||||||
|
useEffect(() => () => { if (signInTimerRef.current) clearTimeout(signInTimerRef.current) }, [])
|
||||||
|
|
||||||
|
// Stable key for roadmapItems identity — avoids unstable array reference in deps
|
||||||
|
const roadmapIdKey = roadmapItems.map((i) => i._id).join(',')
|
||||||
|
|
||||||
// Fetch vote state when the What's Next tab is first viewed
|
// Fetch vote state when the What's Next tab is first viewed
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTab !== 'whats-next' || votesFetched || roadmapItems.length === 0) return
|
if (activeTab !== 'whats-next' || votesFetched || !roadmapIdKey) return
|
||||||
setVotesFetched(true)
|
setVotesFetched(true)
|
||||||
|
|
||||||
const ids = roadmapItems.map((i) => i._id).join(',')
|
fetch(`/api/roadmap/votes?ids=${encodeURIComponent(roadmapIdKey)}`, {
|
||||||
fetch(`/api/roadmap/votes?ids=${encodeURIComponent(ids)}`, {
|
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
})
|
})
|
||||||
.then((r) => (r.ok ? r.json() : {}))
|
.then((r) => (r.ok ? r.json() : {}))
|
||||||
@@ -72,12 +78,13 @@ export function ChangelogTabs({
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
// Spring Boot not yet available — silently keep count=0
|
// Spring Boot not yet available — silently keep count=0
|
||||||
})
|
})
|
||||||
}, [activeTab, votesFetched, roadmapItems])
|
}, [activeTab, votesFetched, roadmapIdKey]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
async function handleVote(id: string) {
|
async function handleVote(id: string) {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
if (signInTimerRef.current) clearTimeout(signInTimerRef.current)
|
||||||
setShowSignInPrompt(true)
|
setShowSignInPrompt(true)
|
||||||
setTimeout(() => setShowSignInPrompt(false), 4000)
|
signInTimerRef.current = setTimeout(() => setShowSignInPrompt(false), 4000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user