How to revalidateTag without API routes?
Unanswered
Oak saucer gall posted this in #help-forum
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Oak saucer gallOP
I have try to revalidate user settings, but the changes only reflect in database, i need to relog to apply the changes..
How can i define an tag user for example, to revalidate later?
How can i define an tag user for example, to revalidate later?
export async function getUserByEmail(email: string) {
try {
return await db.user.findUnique({ where: { email } });
} catch (error) {
return null;
}
}
export async function updateProfile(state: UpdateProfile, formData: FormData) {
const validatedFields = UpdateProfileSchema.safeParse({
image: formData.get('image') || null,
})
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
error: 'Invalid fields.',
success: '',
}
}
const { image } = validatedFields.data;
const blob = await put(image.name, image, { access: 'public' })
const user = await currentUser();
if (!user) {
return { error: 'Unauthorized.', success: '' }
}
const dbUser = await getUserById(user.id);
if (!dbUser) {
return { error: 'Unauthorized.', success: '' }
}
if (user.id !== dbUser.id) {
return { error: 'Unauthorized', success: '' }
}
try {
const updatedUser = await db.user.update({
where: { id: dbUser.id },
data: {
image: blob.url,
firstName,
lastName,
}
});
update({
user: {
image: updatedUser.image,
}
});
// revalidateTag('user');
return { error: '', success: 'Profile updated with successfully!' }
} catch (error) {
throw error
}
}
10 Replies
![Avatar](https://cdn.discordapp.com/avatars/743561772069421169/3c5d689eee4459a24fc420063411c016.webp?size=256)
Ray
you could use
https://nextjs.org/docs/app/api-reference/functions/unstable_cache
unstable_cache
to tag the db queryhttps://nextjs.org/docs/app/api-reference/functions/unstable_cache
like this
export const getUserByEmail = (email: string) => {
return unstable_cache(
async (email: string) => {
return await db.user.findUnique({ where: { email } });
},
[`user-by-email`],
{ tags: [`user-by-email-${email}`] }
)(email);
};
and revalidate it like this
revalidateTag(`user-by-email-user1@user.com`);
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Oak saucer gallOP
Iam wrong? why doesnt work?
async function getUserByEmail(email: string) {
try {
return await db.user.findUnique({ where: { email } });
} catch (error) {
return null;
}
}
export const getCachedUserByEmail = unstable_cache((email) => getUserByEmail(email), ['user'])
// ...
try {
const updatedUser = await db.user.update({
where: { id: dbUser.id },
data: {
image: blob.url,
firstName,
lastName,
}
});
update({
user: {
image: updatedUser.image,
firstName: updatedUser.firstName,
lastName: updatedUser.lastName,
}
});
revalidateTag('user');
return { error: '', success: 'Profile updated with successfully!' }
} catch (error) {
throw error
}
}
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Multiflora rose seed chalcid
This might help https://www.youtube.com/watch?v=VBlSe8tvg4U
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Oak saucer gallOP
In the case of using next auth, is it considered bad practice to use user information in the token, such as name, email and image? Because whenever I change the image, for example, for it to be reflected properly it is necessary to relog the application, not even CTRL + F5 can help.
Furthermore, if I try to use unstable_cache it gives me an error.
error:
Furthermore, if I try to use unstable_cache it gives me an error.
export const cacheGetUserById = unstable_cache(
async (id: string) => {
return await db.user.findUnique({ where: { id } });
},
['user'],
{
tags: ['user']
}
)
error:
[auth][error] JWTSessionError: Read more at https://errors.authjs.dev#jwtsessionerror
[auth][cause]: Error: Invariant: incrementalCache missing in unstable_cache async (id)=>{
return await _lib_db__WEBPACK_IMPORTED_MODULE_0__.db.user.findUnique({
where: {
id
}
});
}
at cachedCb (webpack-internal:///(middleware)/./node_modules/next/dist/esm/server/web/spec-extension/unstable-cache.js:37:19)
at Object.jwt (webpack-internal:///(middleware)/./app/auth/auth.config.ts:58:92)
at Module.session (webpack-internal:///(middleware)/./node_modules/@auth/core/lib/actions/session.js:30:43)
at async AuthInternal (webpack-internal:///(middleware)/./node_modules/@auth/core/lib/index.js:50:24)
at async Auth (webpack-internal:///(middleware)/./node_modules/@auth/core/index.js:123:29)
at async handleAuth (webpack-internal:///(middleware)/./node_modules/next-auth/lib/index.js:81:29)
at async adapter (webpack-internal:///(middleware)/./node_modules/next/dist/esm/server/web/adapter.js:176:16)
at async runWithTaggedErrors (/root/templates/auth-template/node_modules/next/dist/server/web/sandbox/sandbox.js:99:24)
at async DevServer.runMiddleware (/root/templates/auth-template/node_modules/next/dist/server/next-server.js:1035:24)
at async DevServer.runMiddleware (/root/templates/auth-template/node_modules/next/dist/server/dev/next-dev-server.js:260:28)
[auth][details]: {}
auth.config.ts:
async jwt({ token }) {
if (!token.sub) return token;
const user = await cacheGetUserById(token.sub);
if (!user) return token;
const existingAccount = await getAccountById(user.id);
if (user) {
token.firstName = user.firstName;
token.lastName = user.lastName;
token.email = user.email;
token.emailVerified = user.emailVerified;
token.role = user.role as UserRole;
token.isTwoFactorEnabled = user.isTwoFactorEnabled;
token.isOAuth = !!existingAccount;
}
return token;
},
session({ session, token }) {
if (token.sub) {
session.user.id = token.sub
}
if (session.user) {
session.user.firstName = token.firstName;
session.user.lastName = token.lastName;
session.user.email = token.email;
session.user.emailVerified = !!token.emailVerified;
session.user.isTwoFactorEnabled = !!token.isTwoFactorEnabled;
session.user.isOAuth = !!token.isOAuth;
session.user.role = token.role;
}
return session;
},
update-profile page:
update-user form:
import { auth } from "#/app/auth/providers";
import { UserProfile } from "#/components/user/account/user-profile";
export default async function UpdateProfilePage() {
const session = await auth();
return (
<main className="w-full max-w-screen-md mx-auto border rounded bg-gray-50">
<UserProfile user={session?.user} />
</main>
)
}
update-user form:
export function UpdateUserForm({ user }: User) {
const [state, dispatch] = useFormState(updateProfile, initialState)
const username = `${user.firstName} ${user.lastName}`
return (
<form action={dispatch} className="grid gap-6">
<UpdateAvatar username={username} image={user.image} />
<div className="grid gap-1">
<label htmlFor="">First name</label>
<Input type="text" name="firstName" defaultValue={user.firstName} />
</div>
<div className="grid gap-1">
<label htmlFor="">Last name</label>
<Input type="text" name="lastName" defaultValue={user.lastName} />
</div>
<FormError message={state.error} />
<FormSuccess message={state.success} />
<div className="flex gap-4 items-center">
<Button variant="ghost">Cancel</Button>
<Button>Update profile</Button>
</div>
</form>
)
}
![Avatar](https://cdn.discordapp.com/avatars/743561772069421169/3c5d689eee4459a24fc420063411c016.webp?size=256)
Ray
export const getCachedUserByEmail = unstable_cache((email) => getUserByEmail(email), ['user'], { tags: ['user'] })
you didn't set the tag for it