Skip to content

Commit

Permalink
fix: onResolved + scroll restoration
Browse files Browse the repository at this point in the history
  • Loading branch information
tannerlinsley committed Dec 6, 2023
1 parent 2e1d658 commit a757323
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 31 deletions.
38 changes: 36 additions & 2 deletions examples/react/deferred-data/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Await,
defer,
ErrorRouteProps,
MatchRoute,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
import axios from 'axios'
Expand Down Expand Up @@ -65,6 +66,20 @@ const fetchPost = async (postId: string) => {
}
}

function Spinner({ show, wait }: { show?: boolean; wait?: `delay-${number}` }) {
return (
<div
className={`inline-block animate-spin px-3 transition ${
show ?? true
? `opacity-1 duration-500 ${wait ?? 'delay-300'}`
: 'duration-500 opacity-0 delay-0'
}`}
>
</div>
)
}

const rootRoute = new RootRoute({
component: RootComponent,
})
Expand Down Expand Up @@ -135,10 +150,21 @@ function PostsComponent() {
params={{
postId: post.id,
}}
className="block py-1 text-blue-800 hover:text-blue-600"
className="flex py-1 text-blue-800 hover:text-blue-600 gap-2 items-center"
activeProps={{ className: 'text-black font-bold' }}
>
<div>{post.title.substring(0, 20)}</div>
<MatchRoute
to={postRoute.to}
params={{
postId: post.id,
}}
pending
>
{(match) => {
return <Spinner show={!!match} wait="0" />
}}
</MatchRoute>
</Link>
</li>
)
Expand Down Expand Up @@ -176,7 +202,15 @@ function PostComponent() {
<div className="space-y-2">
<h4 className="text-xl font-bold underline">{post.title}</h4>
<div className="text-sm">{post.body}</div>
<React.Suspense fallback={<div>Loading comments...</div>} key={post.id}>
<React.Suspense
fallback={
<div className="flex items-center gap-2">
<Spinner />
Loading comments...
</div>
}
key={post.id}
>
<Await promise={commentsPromise}>
{(comments) => {
return (
Expand Down
6 changes: 0 additions & 6 deletions examples/react/scroll-restoration/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ const rootRoute = new RootRoute({
})

function RootComponent() {
// const {
// state: { location, resolvedLocation },
// } = useRouter()
return (
<>
<div className="p-2 flex gap-2 sticky top-0 bg-white border-b">
Expand All @@ -37,9 +34,6 @@ function RootComponent() {
By-Element
</Link>
</div>
{/* <pre className="text-[.5rem]">
<code>{JSON.stringify({ resolvedLocation, location }, null, 2)}</code>
</pre> */}
<Outlet />
<ScrollRestoration />
<TanStackRouterDevtools />
Expand Down
6 changes: 3 additions & 3 deletions packages/react-router/src/Matches.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ export interface RouteMatch<
export type AnyRouteMatch = RouteMatch<any>

export function Matches() {
const { routesById } = useRouter()
const router = useRouter()
const routerState = useRouterState()
const matches = routerState.pendingMatches?.some((d) => d.showPending)
? routerState.pendingMatches
: routerState.matches
const locationKey = useRouterState().location.state.key
const route = routesById[rootRouteId]!
const locationKey = router.latestLocation.state.key
const route = router.routesById[rootRouteId]!

const errorComponent = React.useCallback(
(props: any) => {
Expand Down
65 changes: 45 additions & 20 deletions packages/react-router/src/RouterProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
RouterOptions,
RouterState,
} from './router'
import { NoInfer, PickAsRequired, useLayoutEffect } from './utils'
import { NoInfer, PickAsRequired, pick, useLayoutEffect } from './utils'
import { MatchRouteOptions } from './Matches'
import { RouteMatch } from './Matches'

Expand Down Expand Up @@ -87,7 +87,11 @@ export function RouterProvider<
},
} as any)

const inner = <RouterProviderInner<TRouteTree, TDehydrated> router={router} />
const inner = (
<routerContext.Provider value={router}>
<RouterProviderInner<TRouteTree, TDehydrated> router={router} />
</routerContext.Provider>
)

if (router.options.Wrap) {
return <router.options.Wrap>{inner}</router.options.Wrap>
Expand All @@ -100,6 +104,21 @@ function RouterProviderInner<
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
TDehydrated extends Record<string, any> = Record<string, any>,
>({ router }: RouterProps<TRouteTree, TDehydrated>) {
return (
<>
<Matches />
<Transitioner />
</>
)
}

function Transitioner() {
const router = useRouter()
const routerState = useRouterState({
select: (s) =>
pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning']),
})

const [isTransitioning, startReactTransition] = React.useTransition()

router.startReactTransition = startReactTransition
Expand All @@ -114,19 +133,27 @@ function RouterProviderInner<
}, [isTransitioning])

const tryLoad = () => {
// startReactTransition(() => {
try {
router.load()
} catch (err) {
console.error(err)
const apply = (cb: () => void) => {
if (!routerState.isTransitioning) {
startReactTransition(() => cb())
} else {
cb()
}
}
// })

apply(() => {
try {
router.load()
} catch (err) {
console.error(err)
}
})
}

useLayoutEffect(() => {
const unsub = router.history.subscribe(() => {
router.latestLocation = router.parseLocation(router.latestLocation)
if (router.state.location !== router.latestLocation) {
if (routerState.location !== router.latestLocation) {
tryLoad()
}
})
Expand All @@ -138,7 +165,7 @@ function RouterProviderInner<
state: true,
})

if (router.state.location.href !== nextLocation.href) {
if (routerState.location.href !== nextLocation.href) {
router.commitLocation({ ...nextLocation, replace: true })
}

Expand All @@ -150,14 +177,16 @@ function RouterProviderInner<
useLayoutEffect(() => {
if (
!isTransitioning &&
router.state.resolvedLocation !== router.state.location
!routerState.isLoading &&
routerState.resolvedLocation !== routerState.location
) {
console.log('onResolved', routerState.location)
router.emit({
type: 'onResolved',
fromLocation: router.state.resolvedLocation,
toLocation: router.state.location,
fromLocation: routerState.resolvedLocation,
toLocation: routerState.location,
pathChanged:
router.state.location!.href !== router.state.resolvedLocation?.href,
routerState.location!.href !== routerState.resolvedLocation?.href,
})
router.pendingMatches = []

Expand All @@ -167,19 +196,15 @@ function RouterProviderInner<
resolvedLocation: s.location,
}))
}
}, [isTransitioning])
}, [isTransitioning, routerState.isLoading])

useLayoutEffect(() => {
if (!window.__TSR_DEHYDRATED__) {
tryLoad()
}
}, [])

return (
<routerContext.Provider value={router}>
<Matches />
</routerContext.Provider>
)
return null
}

export function getRouteMatch<TRouteTree extends AnyRoute>(
Expand Down

0 comments on commit a757323

Please sign in to comment.