react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Bug]: ScrollRestoration does not go to page top when redirecting in an action

Open john-evan08 opened this issue 3 years ago • 3 comments

What version of React Router are you using?

6.4.3

Steps to Reproduce

<Route 
     path="/"
     element={
	<div>
		<ScrollRestoration />
		<Outlet />
	</div>
	}
>
            <Route
	            path="post_route"
	            action={async ({ params }) => {
                           await patchServer()
	                  return redirect(`redirect_route`)
                     }}
            />

</Route>

The action is called with a <Form method="patch"/>

Expected Behavior

The action is called and redirect to the url redirect_route, but without scrolling to the top... I expected the page to scroll to the top when calling the action (and returning the redirect)

Actual Behavior

The action is called and the page redirects to the new route, but without scrolling to the top (it stays at the same place)

john-evan08 avatar Nov 09 '22 16:11 john-evan08

Hm, yeah by default scroll restoration is skipped on submissions, but if you redirect from an action that should probably re-enable it. We would then likely need to add preventScrollReset to <Form> like we have on <Link> as well.

brophdawg11 avatar Nov 17 '22 17:11 brophdawg11

@brophdawg11 Thank you !! I am not sure I understood anything. How should I fix this issue in my case ?

john-evan08 avatar Nov 24 '22 10:11 john-evan08

I think it's a bug, so I don't think there's a way to work around it at the moment unfortunately. We'll try to get to it in an upcoming release, but if you or anyone else was interested in taking a stab at a PR, I think the change would happen in completeNavigation in packages/router/router.ts.

Right now, we always disable scroll restoration on submissions:

updateState({
  ...
  restoreScrollPosition: state.navigation.formData
    ? false
    : getSavedScrollPosition(location, newState.matches || state.matches),
});

But that's incorrectly including redirects after submissions because the formData sticks around. I think that probably needs to become something like the following to only prevent scroll restoration when the new location matches the location the form was submitted to (meaning the action didn't redirect):

let preventScrollRestoration = (
  state.navigation.formData && 
  location.pathname + location.search === state.navigation.formAction
);

updateState({
  ...
  restoreScrollPosition: preventScrollRestoration
    ? false
    : getSavedScrollPosition(location, newState.matches || state.matches),
});

brophdawg11 avatar Nov 28 '22 14:11 brophdawg11

I have been trying to fix this but to no avail via patch-package. Specifically I made the above changes locally, built the router package and copied the files over to my node_modules/@remix-run/router folder of my project. However the changes do not seem to make any difference.

Is there anything I am missing here?

This bug is quite problematic in terms of ux in my app.

ferdinandsalis avatar Jan 03 '23 23:01 ferdinandsalis

Hi, I encounter the same issue.

The fix proposed by @brophdawg11 seems to solve the problem for me so I've made a PR.

jrakotoharisoa avatar Jan 04 '23 22:01 jrakotoharisoa

This is now released in a 6.7.0-pre.1 prerelease if you want to give it a shot to see if it fixes your issues. The stable should be out early next week hopefully.

brophdawg11 avatar Jan 11 '23 21:01 brophdawg11

Thanks, this release fix my issue 🙂

jrakotoharisoa avatar Jan 13 '23 08:01 jrakotoharisoa

Released in 6.7.0

brophdawg11 avatar Jan 18 '23 20:01 brophdawg11