How to use next.js router.push() properly with an useQuery custom hook call?
Hi all, I am wondering what is the best way to redirect to another page when calling a custom hook that uses useQuery. Specifically, on the dashboard page of an app I am calling useCognitoUser to check if there is a current user logged in. If a user is not logged in an error will be returned from the fetch and I want to route the user to the login page. See custom hook below.
export function useCognitoUser({
onSuccess,
onError,
}: UseCognitoUserProps = {}) {
return useQuery({
queryKey: ['cognitoUser'],
queryFn: async () => {
const { attributes } = await Auth.currentAuthenticatedUser()
return attributes as CognitoUserAttributes
},
onSuccess,
onError,
})
}
Currently, when this hook is called on the dashboard page I am using an onError callback to route to the login page if there is no current user logged in, see below.
export default function DashboardPage() {
const router = useRouter()
const cognitoUser = useCognitoUser({
onError() {
router.push('/auth/login')
},
})
However, with this implementation, for some reason when I trigger an error for the 'cognitoUser' query in the react-query dev tools, I am not getting the routing to the login page for testing purposes, although it does work properly outside of the dev tools context when an non-logged in user tries to navigate to the dashboard page. I am wondering if instead I should do the routing inside of an if (cognitoUser.isError) conditional. This implementation does work to route to the login page when an error is triggered with the dev tools and routes back to the dashboard page when the error is restored. My opposition to using this implementation is I know it is not best practice to cause side effects like this.
export default function DashboardPage() {
const router = useRouter()
const cognitoUser = useCognitoUser()
if (cognitoUser.isError) {
router.push('/auth/login')
}
Any thoughts/insight on this would be much appreciated.
3 Replies
genetic-orange•3y ago
The callbacks on useQuery (onError and onSuccess) are deprecated, please don't use them
fair-roseOP•3y ago
@TkDodo 🔮 Got it! So is it safe to assume that routing should be accomplish via the useQuery statuses and returned data even though as I understand side effects are not normally meant to be to be called this way? For example,
export default function LoginPage() {
const router = useRouter()
const cognitoUser = useCognitoUser()
if (cognitoUser.isSuccess) {
router.push('/dashboard')
}
and
export default function DashboardPage() {
const router = useRouter()
const cognitoUser = useCognitoUser()
if (cognitoUser.isError) {
router.push('/auth/login')
}
const user = useGetUser({
id: cognitoUser.data?.sub
})
Thanks for your help!
fair-rose•3y ago
Personally, I would either try to move the cognito call to a route loader and return a redirect in case of error, or if that's not possible, add a try/catch inside the queryFn and hard redirect (
window.location.href="/auth/login") in case of auth error.
Otherwise I think router.push() needs to be wrapped in a useEffect().