You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What is the new or updated feature that you are suggesting?
Making UNSAFE_LocationContext available publicly.
Background
I am currently using React Router to manage page transitions for my web app, and for animations on route transition I am using React Transition Group. I know that as of RRv6 it's become somewhat difficult to implement CSS Transitions the way that it could be done in v5. While I think I may have come up with a solution, the caveat here is that it makes use of some of React Router's internal apis, which I would like to discuss here.
Code
/** * Component wrapper that provides Animation on route transition. */functionAnimatedTransition(props: React.PropsWithChildren<{routeObjects?: RouteObject[];animationConfig?: AnimationConfig}>): JSX.Element{/** * React Router has two ways to render routes: * 1. via the <Routes/> component/useRoutes hook. Both root and child routes can be rendered this way. * 2. via an <Outlet/> component. These components render content associated with children Route elements only. * We want to support transitions for both these cases in tandem, which we can do by separating routing logic for root * routes and children routes: * - When 'routeObjects' are provided, generate the CSSTransition key from the first match of these routeObjects. * This will handle transitions for top-level routes only. * - Otherwise, generate the CSSTransition key based on the first subPath of the remainingPathname. This allows * us to handle immediate child routes, but also not cause transitions when transitioning to further nested * child routes. */constlocation=useLocation();constnavigationType=useNavigationType();const{pathname: parentPathnameBase}=useResolvedPath('');constpathname=location.pathname||'/';constremainingPathname=parentPathnameBase!=='/'&&pathname.startsWith(parentPathnameBase)
? pathname.slice(parentPathnameBase.length)||'/'
: pathname;constmatches=matchRoutes(props.routeObjects||[],{pathname: remainingPathname,});constkey=props.routeObjects ? matches&&matches[0].pathnameBase : remainingPathname.split('/')[1];return(<TransitionGroupappear={!!props.routeObjects}component={null}childFactory={(child)=>props.animationConfig
? React.cloneElement(child,props.animationConfig)
: child}><CSSTransitiontimeout={0}key={key}><UNSAFE_LocationContext.Providervalue={{ location, navigationType }}>{props.children}</UNSAFE_LocationContext.Provider></CSSTransition></TransitionGroup>);}/** * Renders an <Routes/> component that supports Animations. */exportfunctionAnimatedRoutes(props: {routeObjects: RouteObject[];animationConfig?: AnimationConfig}): JSX.Element{constroutes=useRoutes(props.routeObjects);return(<AnimatedTransitionanimationConfig={props.animationConfig}routeObjects={props.routeObjects}>{routes}</AnimatedTransition>);}/** * Renders an <Outlet/> component that supports Animations. */exportfunctionAnimatedOutlet(props: OutletProps&{animationConfig?: AnimationConfig}): JSX.Element{// <Outlet> components get their context based a RouteContext that updates on location change. Passing it into// <AnimatedTransition/> directly will result in a phenomenon where the onExit content will re-render to be the// onEnter content, giving the impression of transitioning from one page to the exact same page.// We can prevent this by getting the outlet content outside of AnimatedTransition and passing this object in instead.constoutlet=useOutlet(props.context);return<AnimatedTransitionanimationConfig={props.animationConfig}>{outlet}</AnimatedTransition>;}
Manually setting LocationContext
As you can see, I use UNSAFE_LocationContext within the AnimatedTransition component. The reason is that when a component within a TransitionGroup has a key update, the new-keyed content (onEnter) is rendered alongside the old-keyed content (onExit). However, if the content has a descendant component that relies on the useLocation or useSearchParams hooks, the component will reference the current URL, even within the onExit component.
Clicking the Next button while on the test_A route will cause the current content to immediately change to "Welcome to test_B" , even before the transition has finished.
I've found that they way around this is to set the location context of the component within TransitionGroup to the location from the scope in which the component is declared, which seems only possible with UNSAFE_LocationContext.
Rendering with Outlets
Using Outlets with AnimatedTransition seemed straightforward enough, but I noticed that on transition, the onExit component would always have its content change to reflect outlet content at the current location, giving the impression of transitioning to duplicate screen. This occurs regardless of whether or not UNSAFE_LocationContext is used.
I was able to get animations working properly by using the useOutlet hook, but I want to ask: is there something I am missing here? Is there perhaps a better way to guarantee that onExit outlet context reflects the route the outlet is reference at the time the route was entered?
Why should this feature be included?
It seems to me that being able to set LocationContext freely in this manner is actually really useful, so I was curious if it would be possible to make this okay for public/normal use?
The text was updated successfully, but these errors were encountered:
@timdorr I can see similarities between this and #8470, but it seems like for that issue, it was solved by using UNSAFE_LocationContext, whereas this topic is more about providing the LocationContext as a safe to use API (i.e. promoting it from an purely internal API).
I only provide the Animation Transition as an example to show the merits of using UNSAFE_LocationContext, but I do think that there are potentially other use-cases other than Animations.
What is the new or updated feature that you are suggesting?
Making UNSAFE_LocationContext available publicly.
Background
I am currently using React Router to manage page transitions for my web app, and for animations on route transition I am using React Transition Group. I know that as of RRv6 it's become somewhat difficult to implement CSS Transitions the way that it could be done in v5. While I think I may have come up with a solution, the caveat here is that it makes use of some of React Router's internal apis, which I would like to discuss here.
Code
Manually setting LocationContext
As you can see, I use
UNSAFE_LocationContext
within theAnimatedTransition
component. The reason is that when a component within aTransitionGroup
has a key update, the new-keyed content (onEnter) is rendered alongside the old-keyed content (onExit). However, if the content has a descendant component that relies on theuseLocation
oruseSearchParams
hooks, the component will reference the current URL, even within the onExit component.For example, in the below case:
Clicking the Next button while on the
test_A
route will cause the current content to immediately change to "Welcome to test_B" , even before the transition has finished.I've found that they way around this is to set the location context of the component within
TransitionGroup
to the location from the scope in which the component is declared, which seems only possible withUNSAFE_LocationContext
.Rendering with Outlets
Using Outlets with
AnimatedTransition
seemed straightforward enough, but I noticed that on transition, the onExit component would always have its content change to reflect outlet content at the current location, giving the impression of transitioning to duplicate screen. This occurs regardless of whether or notUNSAFE_LocationContext
is used.I was able to get animations working properly by using the
useOutlet
hook, but I want to ask: is there something I am missing here? Is there perhaps a better way to guarantee that onExit outlet context reflects the route the outlet is reference at the time the route was entered?Why should this feature be included?
It seems to me that being able to set LocationContext freely in this manner is actually really useful, so I was curious if it would be possible to make this okay for public/normal use?
The text was updated successfully, but these errors were encountered: