I am working on migrating my app to React Router v6. I can't believe how many breaking changes they introduced with that! Hope they never do that again!
So I need to have some pages of the app private, that we are just authenticating with a basic password. I have followed the tutorial here: https://blog.logrocket.com/complete-guide-authentication-with-react-router-v6/ It all made sense and worked well. But now I'm trying to figure out how to route the user to the original requested page after they are logged in. I can't figure out where or how to get the original requested path. I did find this other SO question: React Router - PrivateRoute, redirect to original destination after login but for some reason, I do not have that data in my props.
Here is my useAuth hook where the issue lies:
import { createContext, useContext, useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { useLocalStorage } from './useLocalStorage';
import { authenticateUser } from '../utils/APIFunctions';
const AuthContext = createContext(undefined);
export const AuthProvider = ({ children }) => {
// I did try (props) instead of ({children}), but there
// is only one object called children in props
console.log({ props });
const [token, setToken] = useLocalStorage('token', null);
const navigate = useNavigate();
let location = useLocation();
const login = async (data) => {
const password = data.password;
// check this password in the DB
let error = '';
authenticateUser(password).then((res) => {
console.log({ res });
console.log({ location });
if (res?.status === 200 && res?.data[0]?.auth_level > 0) {
// this is a valid password
const time = Date.now();
// setToken({ token: password + '-' + time });
navigate(??? // this is where I need to put something so it knows where to send the user back to, if i only had one protected route, i could hardcode the path);
} else {
if (res.data.name === 'ConnectionError') {
error = 'Unable to connect to database.';
} else if (res?.data?.ReturnValue === 0) {
} else {
error = 'Error logging into Scheduler.';
}
}
});
//navigate('/baglines', { replace: true });
};
const logout = () => {
setToken(null);
navigate('/', { replace: true });
};
const value = useMemo(
() => ({
token,
login,
logout,
}),
[token]
);
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
return useContext(AuthContext);
};
And here is my ProtectedRoute where useAuth gets used:
import { Navigate } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
export const ProtectedRoute = ({ children, ...rest }) => {
const { token } = useAuth();
// I also tried getting (props) here instead of ({children})
// and once again only one object of 'children'
let pathname = rest; // .location.pathname;
console.log({ pathname });
console.log({ token });
if (!token) {
// user is not authenticated
return <Navigate to={'/login'} />;
}
return children;
};
And lastly, this is how I am implementing the ProtectedRoute:
<Routes>
<Route path={'/'} element={<LandingPage />} />
<Route path={'/login'} element={<Login />} />
<Route
path={'/baglines'}
element={
<ProtectedRoute>
<Scheduling
...
Let me know if any more code is needed from me.