Skip to content

Instantly share code, notes, and snippets.

@Brayden
Last active August 15, 2024 13:18
Show Gist options
  • Save Brayden/e7afa42eebdb1b12f2443d12720ae6aa to your computer and use it in GitHub Desktop.
Save Brayden/e7afa42eebdb1b12f2443d12720ae6aa to your computer and use it in GitHub Desktop.
React useLifecycle Hook
import { useEffect } from 'react'
export enum LifecycleVisibilityChange {
Visible = 'visible',
Hidden = 'hidden',
Prerender = 'prerender',
Unloaded = 'unloaded',
}
export const useLifecycle = ({
onAppear,
onLayout,
onDisappear,
onResize,
onScroll,
onVisibilityChange,
onOrientationChange,
onNetworkStatusChange,
onIdle,
idleTime = 60000,
}: {
onAppear?: () => void
onLayout?: () => void
onDisappear?: () => void
onResize?: () => void
onScroll?: () => void
onVisibilityChange?: (status: LifecycleVisibilityChange) => void
onOrientationChange?: (orientation: string) => void
onNetworkStatusChange?: (isOnline: boolean) => void
onIdle?: () => void
idleTime?: number
}) => {
useEffect(() => {
if (onAppear) {
onAppear()
}
return () => {
if (onDisappear) {
onDisappear()
}
}
}, [onAppear, onDisappear])
useEffect(() => {
if (onLayout) {
const handleLayout = () => {
requestAnimationFrame(() => {
onLayout()
})
}
handleLayout()
}
})
useEffect(() => {
if (onResize) {
const handleResize = () => {
onResize()
}
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}
}, [onResize])
useEffect(() => {
const handleVisibilityChange = () => {
if (onVisibilityChange) {
const lifecycleVisibility =
document.visibilityState as LifecycleVisibilityChange
onVisibilityChange(lifecycleVisibility)
}
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => {
document.removeEventListener(
'visibilitychange',
handleVisibilityChange
)
}
}, [onVisibilityChange])
useEffect(() => {
if (onScroll) {
const handleScroll = () => {
onScroll()
}
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}
}, [onScroll])
useEffect(() => {
if (onIdle) {
let idleTimer: string | number | NodeJS.Timeout | undefined
const resetIdleTimer = () => {
clearTimeout(idleTimer)
idleTimer = setTimeout(() => {
onIdle()
}, idleTime)
}
const events = ['mousemove', 'keydown', 'scroll', 'touchstart']
events.forEach((event) => {
window.addEventListener(event, resetIdleTimer)
})
resetIdleTimer()
return () => {
clearTimeout(idleTimer)
events.forEach((event) => {
window.removeEventListener(event, resetIdleTimer)
})
}
}
}, [onIdle, idleTime])
useEffect(() => {
const handleOrientationChange = () => {
if (onOrientationChange) {
onOrientationChange(window.screen.orientation.type)
}
}
window.addEventListener('orientationchange', handleOrientationChange)
return () => {
window.removeEventListener(
'orientationchange',
handleOrientationChange
)
}
}, [onOrientationChange])
useEffect(() => {
const handleNetworkChange = () => {
if (onNetworkStatusChange) {
onNetworkStatusChange(navigator.onLine)
}
}
window.addEventListener('online', handleNetworkChange)
window.addEventListener('offline', handleNetworkChange)
handleNetworkChange()
return () => {
window.removeEventListener('online', handleNetworkChange)
window.removeEventListener('offline', handleNetworkChange)
}
}, [onNetworkStatusChange])
}
export default useLifecycle
import { useLifecycle } from './hooks/use-lifecycle'
export default function MyComponent() {
useLifecycle({
onAppear: () => {
// Component did mount and appear
},
onLayout: () => {
// Component did a re-render
},
onDisappear: () => {
// Component did unmount and disappear
},
onResize: () => {
// Window was resized
},
onVisibilityChange: (status) => {
// Component visibility changed, possible values:
// 'visible', 'hidden', 'prerender', 'unloaded'
},
onScroll: () => {
// Window was scrolled
},
onOrientationChange: (orientation) => {
// Window orientation changed, possible values:
// 'landscape-primary', 'landscape-secondary', 'portrait-primary', 'portrait-secondary'
},
onNetworkStatusChange: (isOnline) => {
// Network status changed
},
onIdle: () => {
// User has been idle for a while
},
idleTime: 60000, // 60 seconds
})
return <div>My component</div>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment