React Router:登录后跳转原受限路由及回退两页并保留历史
Alright, let's tackle your two React Router challenges here—redirecting back to the protected route after login, and safely navigating back two pages while preserving history. I'll also fix up your existing verifyOTP action code to integrate these solutions.
1. Preserving the Original Protected Route for Post-Login Redirect
When a user tries to access a protected route like /account/dashboard without being logged in, we need to save that original path first so we can send them back there after successful authentication.
Step 1: Store the original path in your protected route guard
Use React Router'sNavigatecomponent to pass the current location as state to the login page:// Inside your ProtectedRoute component import { Navigate, useLocation } from 'react-router-dom'; const ProtectedRoute = ({ children }) => { const { isSignedIn } = useSelector(state => state.user); const location = useLocation(); if (!isSignedIn) { // Send the user to login, and save the original path in state return <Navigate to="/login" state={{ from: location }} />; } return children; };Step 2: Pass the saved path to your verifyOTP action
In your login/OTP verification component, grab the saved path from location state and pass it to the action:// Inside VerifyOTP component const location = useLocation(); const redirectFrom = location.state?.from?.pathname || '/'; // Fallback to homepage // When triggering OTP verification dispatch(verifyOTP(enteredOTP, redirectFrom));
2. Safely Navigating Back Two Pages (With History Preservation)
Your original code uses window.history.go(-2), which works, but we should add a safety check to avoid errors if there aren't enough pages in the history stack. Also, if you're using React Router v6, you'll want to use the navigate function instead of the legacy history object.
3. Updated verifyOTP Action Code
Here's the revised action with both solutions integrated, plus cleaner async/await syntax and a fix for a typo (verfied → verified):
export const verifyOTP = (data, redirectFrom) => async (dispatch, getState) => { const { userId, profileCompleted } = getState().user; try { const response = await svysh.post(`/customer/verify-otp/${userId}`, { otp: Number(data) }); // Extract response data with clearer logic const verified = !response.data.error; const token = verified ? response.data.data.access_token : null; const tokenExpiry = verified ? Date.parse(response.data.data.expires_at) : null; const isSignedIn = !!token; const errorCode = response.data.error ? response.data.code : null; dispatch({ type: actionTypes.VERIFY_OTP, accessToken: token, accessTokenExpiry: tokenExpiry, verified: verified, // Fixed typo from "verfied" isSignedIn: isSignedIn, error: response.data.error, errorCode: errorCode, message: response.data.message }); dispatch(setLoading(false)); if (verified) { if (!profileCompleted) { // Send user to complete profile first history.push('/complete-profile'); } else { // Prioritize redirecting back to the original protected route if (redirectFrom) { history.push(redirectFrom); } else { // Fallback: go back two pages, with safety check if (window.history.length >= 3) { // Ensure we have enough history entries to go back 2 pages history.go(-2); } else { // If not, redirect to homepage as a fallback history.push('/'); } } } } else { // OTP failed, send back to verification page history.push('/verify'); } } catch (error) { console.log('Catch Error', error); dispatch(setLoading(false)); } };
Key Improvements:
- Protected route redirect: We now prioritize sending the user back to their original intended route after successful login/OTP verification.
- Safety for back navigation: Added a check to ensure we don't try to go back more pages than exist in the history stack.
- Cleaner code: Swapped
.then/.catchfor async/await for better readability, fixed a typo in the action payload, and simplified response data extraction. - Fallback logic: Added a homepage fallback for cases where there's no saved redirect path or insufficient history entries.
For React Router v6 Users:
If you're using React Router v6, replace the history object with the navigate function from useNavigate():
- Pass
navigateas an additional parameter to your action from the component. - Replace
history.push(path)withnavigate(path)andhistory.go(-2)withnavigate(-2).
Example component usage for v6:
import { useNavigate, useLocation } from 'react-router-dom'; const VerifyOTP = () => { const navigate = useNavigate(); const location = useLocation(); const redirectFrom = location.state?.from?.pathname || '/'; const handleVerify = (otp) => { dispatch(verifyOTP(otp, redirectFrom, navigate)); }; // ... rest of component };
Then update the action to use navigate instead of history:
export const verifyOTP = (data, redirectFrom, navigate) => async (dispatch, getState) => { // ... existing logic if (verified) { if (!profileCompleted) { navigate('/complete-profile'); } else { if (redirectFrom) { navigate(redirectFrom); } else { if (window.history.length >= 3) { navigate(-2); } else { navigate('/'); } } } } else { navigate('/verify'); } // ... rest of logic };
内容的提问来源于stack exchange,提问作者Fahad Sohail

