T
TanStack3y ago
extended-salmon

Mutating on visiting a page

Somehow I know what I have created is an abomination. I am trying to build a page that simply logs the user out. I am using Next app router + trpc + trpc's react-query wrapper. First I want to address why I am using a client component and not a server component that logs the user out? Few reasons: 1. Can't set cookies in Next.js in server components 2. It will be a GET request, and my auth solution requires a POST (in order to receive Origin and Host headers)
"use client";

import { trpc } from "$/lib/trpc/client";
import { Spinner } from "@chakra-ui/react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";

export default function LogoutPage() {
const router = useRouter();
const utils = trpc.useUtils();

// Need to wrap in useState to ensure effect doesn't fire many times
const [logout] = useState(
trpc.auth.logout.useMutation({
onSuccess: (data) => {
router.push(data.redirectTo);
router.refresh();
},
onSettled: () => {
// Refetch current user
utils.auth.getCurrentUser.invalidate();
}
})
);

useEffect(() => {
logout.mutate();
}, [logout]);

return <Spinner />;
}
"use client";

import { trpc } from "$/lib/trpc/client";
import { Spinner } from "@chakra-ui/react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";

export default function LogoutPage() {
const router = useRouter();
const utils = trpc.useUtils();

// Need to wrap in useState to ensure effect doesn't fire many times
const [logout] = useState(
trpc.auth.logout.useMutation({
onSuccess: (data) => {
router.push(data.redirectTo);
router.refresh();
},
onSettled: () => {
// Refetch current user
utils.auth.getCurrentUser.invalidate();
}
})
);

useEffect(() => {
logout.mutate();
}, [logout]);

return <Spinner />;
}
Something about this feels off to me, especially using the useEffect. I'm also unclear why I need to wrap the useQuery in useState. Any suggestions for a better way?
3 Replies
eastern-cyan
eastern-cyan3y ago
You cannot create the instance of a hook inside useState!! Wtf Install eslint react hooks to prevent this You should wrap the logout.mutate in a check to prevent this to be fired twice
extended-salmon
extended-salmonOP3y ago
Funny I have eslint react hooks and it didn't show that as an issue. Anyway, refactored to this based on this thread: https://github.com/trojanowski/react-apollo-hooks/issues/205
export default function LogoutPage() {
const router = useRouter();
const utils = trpc.useUtils();

const { mutate } = trpc.auth.logout.useMutation({
onSuccess: (data) => {
router.push(data.redirectTo);
router.refresh();
},
onSettled: () => {
// Refetch current user
utils.auth.getCurrentUser.invalidate();
}
});

useEffect(() => {
mutate();
}, [mutate]);

return <Spinner />;
}
export default function LogoutPage() {
const router = useRouter();
const utils = trpc.useUtils();

const { mutate } = trpc.auth.logout.useMutation({
onSuccess: (data) => {
router.push(data.redirectTo);
router.refresh();
},
onSettled: () => {
// Refetch current user
utils.auth.getCurrentUser.invalidate();
}
});

useEffect(() => {
mutate();
}, [mutate]);

return <Spinner />;
}
GitHub
Calling a mutation within React.useEffect causes infinite loop · Is...
I'm attempting to perform a mutation when a specific route is hit in my application. When using useEffect and passing through a mutation method as a dependancy, it enters an infinite loop. cons...
eastern-cyan
eastern-cyan3y ago
Looks better. I’d wrap the mutate inside ‚if (idle)‘

Did you find this page helpful?