import { useState, useLayoutEffect, useContext, useRef } from 'react' import { unstable_batchedUpdates as batchedUpdates } from 'react-dom' import type { LoadState } from '../../clientTypes' import { dataCacheCtx, setDataCacheCtx } from './ssr/ctx' import { usePageModule } from './state' export default function useAppState(routePath: string) { const dataCache = useContext(dataCacheCtx) const setDataCache = useContext(setDataCacheCtx) const [loadState, setLoadState] = useState(() => { if (dataCache[routePath]) { // this is a ssr or hydration // this page's data has already been loaded return { type: 'loaded', routePath, } } if (routePath === '/internal-404-page') { // this is a ssr or hydration // for the 404 page return { type: '404', routePath, } } return { type: 'loading', routePath, } }) const onLoadState = ( type: LoadState['type'], routePath: string, error?: any ) => setLoadState({ type, routePath, error }) const loading = usePageModule(routePath) const loadingRef = useRef | undefined>() useLayoutEffect(() => { loadingRef.current = loading if (!loading) { onLoadState('404', routePath) } else { // notice that during hmr, dataCache[routePath] may exist if (dataCache[routePath] && !import.meta.hot) { // this is a ssr client render, not hmr onLoadState('loaded', routePath) } else { onLoadState('loading', routePath) loading.then( (page) => loading === loadingRef.current && batchedUpdates(() => { onLoadState('loaded', routePath) setDataCache((prev) => ({ ...prev, [routePath]: page.default, })) }), (error) => loading === loadingRef.current && onLoadState('load-error', routePath, error) ) } } }, [loading]) return loadState }