import { useEffect, useRef, useState } from 'react'
interface PageLifecycleState {
isVisible: boolean
wasEverHidden: boolean
timeHidden: number
timeVisible: number
}
export function usePageLifecycle() {
const [state, setState] = useState<PageLifecycleState>({
isVisible: true,
wasEverHidden: false,
timeHidden: 0,
timeVisible: Date.now()
})
const hiddenTimeRef = useRef<number>(0)
const wasFreezingRef = useRef<boolean>(false)
useEffect(() => {
const handleVisibilityChange = () => {
const now = Date.now()
const isVisible = !document.hidden
if (isVisible) {
// Page became visible
const timeHidden = hiddenTimeRef.current > 0 ? now - hiddenTimeRef.current : 0
setState(prev => ({
...prev,
isVisible: true,
timeVisible: now,
timeHidden
}))
hiddenTimeRef.current = 0
} else {
// Page became hidden
hiddenTimeRef.current = now
setState(prev => ({
...prev,
isVisible: false,
wasEverHidden: true
}))
}
}
const handleFreeze = () => {
wasFreezingRef.current = true
}
const handleResume = () => {
if (wasFreezingRef.current) {
wasFreezingRef.current = false
// Page was suspended, treat as significant event
setState(prev => ({
...prev,
wasEverHidden: true,
timeVisible: Date.now()
}))
}
}
const handlePageShow = () => {
// Page show event (possibly from cache)
}
const handlePageHide = () => {
// Page hide event (possibly being cached)
}
// Add all the event listeners
document.addEventListener('visibilitychange', handleVisibilityChange)
document.addEventListener('freeze', handleFreeze)
document.addEventListener('resume', handleResume)
window.addEventListener('pageshow', handlePageShow)
window.addEventListener('pagehide', handlePageHide)
// Initial state
handleVisibilityChange()
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange)
document.removeEventListener('freeze', handleFreeze)
document.removeEventListener('resume', handleResume)
window.removeEventListener('pageshow', handlePageShow)
window.removeEventListener('pagehide', handlePageHide)
}
}, [])
const shouldRefreshData = (thresholdMs: number = 30000) => {
return state.timeHidden > thresholdMs || wasFreezingRef.current
}
const shouldPreserveState = () => {
// Preserve state if user just switched tabs briefly
return state.wasEverHidden && state.timeHidden < 30000
}
return {
...state,
shouldRefreshData,
shouldPreserveState,
wasRecentlyHidden: state.timeHidden > 0 && state.timeHidden < 5000
}
}