Last active
September 18, 2024 09:34
-
-
Save DennisSmolek/e19c01f9f2dc1ed02fe3d1ae368daedc to your computer and use it in GitHub Desktop.
Adds event notification for the suspense with a little delay
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This creates a wrapper around suspense to notify when the transition takes place | |
| import { | |
| Suspense as ReactSuspense, | |
| useState, | |
| useEffect, | |
| useCallback, | |
| useMemo, | |
| useRef, | |
| } from "react"; | |
| interface SuspenseProps { | |
| children: React.ReactNode; | |
| onChange?: (status: boolean) => void; | |
| onRender?: () => void; | |
| onFallback?: () => void; | |
| fallback?: React.ReactNode; | |
| delay?: number; | |
| } | |
| export const Suspense: React.FC<SuspenseProps> = ({ | |
| children, | |
| onChange, | |
| onRender, | |
| onFallback, | |
| fallback, | |
| delay, | |
| }) => { | |
| const [isLoaded, setIsLoaded] = useState(false); | |
| const oldIsLoaded = useRef(false); | |
| //const initTime = useMemo(() => performance.now(), []); | |
| const timeoutHolder = useRef(null); | |
| // handle all possible props to notify | |
| const notifyChange = useCallback( | |
| (status: boolean) => { | |
| if (onChange) onChange(status); | |
| if (onRender && status) onRender(); | |
| if (onFallback && !status) onFallback(); | |
| }, | |
| [onChange, onRender, onFallback] | |
| ); | |
| // fire the changes | |
| useEffect(() => { | |
| if (oldIsLoaded.current === isLoaded) return; | |
| oldIsLoaded.current = isLoaded; | |
| // we are going to throttle changes to state | |
| if (timeoutHolder.current) clearTimeout(timeoutHolder.current); | |
| timeoutHolder.current = setTimeout(() => { | |
| notifyChange(isLoaded); | |
| }, delay || 200); | |
| }, [notifyChange, isLoaded, delay]); | |
| return ( | |
| <ReactSuspense | |
| fallback={ | |
| <OnRender | |
| fallback={fallback} | |
| onRender={() => setIsLoaded(false)} | |
| /> | |
| }> | |
| {children} | |
| <OnRender onRender={() => setIsLoaded(true)} /> | |
| </ReactSuspense> | |
| ); | |
| }; | |
| interface OnRenderProps { | |
| onRender: () => void; | |
| fallback?: React.ReactNode; | |
| } | |
| const OnRender: React.FC<OnRenderProps> = ({ onRender, fallback }) => { | |
| useEffect(() => onRender(), [onRender]); | |
| return fallback; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment