Next.js Discord

Discord Forum

Cookies update on page reload

Answered
Siberian posted this in #help-forum
Open in Discord
SiberianOP
Hi there. I want to update cookie expiration time on page reload. However calling it in my page.tsx or extracted "use server" function is yelling about server stuff on render
Answered by Ray
// middleware.ts
export async function middleware(request: NextRequest) {
  const uuid = request.cookies.get("uuid");
  if (uuid?.value) {
    const newExpiration = new Date();
    newExpiration.setMinutes(newExpiration.getMinutes() + 15);

    const ticketId = "";

    sql`
      UPDATE basket
      SET date = ${newExpiration.toISOString()}
      WHERE (uuid =${uuid.value}) AND (ticket_code =${ticketId})
      `;

    const res = new NextResponse();
    res.cookies.set({
      name: "uuid",
      value: uuid.value,
      expires: newExpiration,
    });
    return res;
  }
}
View full answer

54 Replies

SiberianOP
?
Largehead hairtail
Hi @Ratonero Bodeguero Andaluz ,
Check this doc
You can set the expires for cookies.
Original message was deleted
SiberianOP
I have a cookie named 'uuid' which contains uuidv4 as a value and its expiration is set to 15min

Every time user reloads page I want that expiration time to 'reset' back to 15min if that cookie still exists

Its working when I put a function with "use server" on a client side inside useEffect, but preferably I would do this on server side
Largehead hairtail
and also cookies is server action, so you should use it in server component or api route
@Largehead hairtail and also `cookies` is server action, so you should use it in server component or api route
SiberianOP
Yeah, I know how to set up a cookie, but updating it with either server-action funcion or api route doesnt work, first one is yelling about waterfall on render, second is just not doing anything to a cookie
Largehead hairtail
Share me your code here.
SiberianOP
//  api/route.ts
import { cookies } from "next/headers";

export async function POST(req: Request){
    const {uuid,newExpiration} = await req.json();
  const date = new Date(newExpiration)

cookies().set('uuid',uuid.value,{expires:date})
return Response.json(true)
}
//  page.tsx
  const newExpiration = new Date();
  newExpiration.setMinutes(newExpiration.getMinutes() + 15);
  if(uuid){
    //TODO: UPDATE COOKIES
    const res = await fetch(`http://192.168.8.112:3000/${params.slug}/api`,{
      method:'POST',
      body:JSON.stringify({uuid,newExpiration})
    })
    console.log(res)
      sql`
      UPDATE basket
      SET date = ${newExpiration.toISOString()}
      WHERE (uuid =${uuid.value}) AND (ticket_code =${params.slug})
      `
     }
    
Largehead hairtail
export const POST = async (req: Request) => {
  const body = await req.json();

  const response = NextResponse.json({
    success: true,
  });

  response.cookies.set(body.name, body.value);

  return response;
};
reference this example if you prefer to use api route.
I hope above practice helps you.
SiberianOP
I would rather not be calling api on server side
Largehead hairtail
Ah, I suggest to delete old and create new.
@Largehead hairtail Ah, I suggest to delete old and create new.
SiberianOP
well its not working in any way, changed name and value and it didnt add new cookie
but its in response
Best if I could just call a function that would deal with it
Largehead hairtail
If you prefer function to api, you should use server action.
@Largehead hairtail If you prefer function to api, you should use server action.
SiberianOP
its funny actually. it gives me this error
[Error]: Cookies can only be modified in a Server Action or Route Handler.
Largehead hairtail
// common.ts
'use server';
import { cookies } from 'next/headers';

export const setCookie = async (name: string, value: string) => {
  cookies().set(name, value)
}
SiberianOP
and this is my server-action.ts file
"use server";

import { sql } from "@vercel/postgres";
import { RequestCookie } from "next/dist/compiled/@edge-runtime/cookies";
import { cookies } from "next/headers";

export const updateCookie = async (uuid:RequestCookie,ticketId:string) =>{
  const newExpiration = new Date();
  newExpiration.setMinutes(newExpiration.getMinutes() + 15);
  if(uuid){
    //TODO: UPDATE COOKIES
    cookies().delete('uuid')
    cookies().set('uuid',uuid.value,{expires:newExpiration})

      sql`
      UPDATE basket
      SET date = ${newExpiration.toISOString()}
      WHERE (uuid =${uuid.value}) AND (ticket_code =${ticketId})
      `
     }
}
is it even possible to update cookie from server, or should it be done only on client side (calling server by serverAction or apiRoute)?
Largehead hairtail
cookies is server action, so if you want to call the func in client, you should make server action common file like above my practice.
SiberianOP
yes, but my page.tsx is not using client with "use client"
 Error: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
    at setCookie (./src/server-actions/sql/common.ts:15:61)
use cookies-next library
Largehead hairtail
Yeah, look at the error message.
That says the func is called in client component.
@averydelusionalperson use cookies-next library
SiberianOP
going to read about it
@Largehead hairtail That says the func is called in client component.
SiberianOP
where it says that?
Largehead hairtail
Error: Cookies can only be modified in a Server Action or Route Handler
SiberianOP
so basically cookies can be modified only on client-side?
Largehead hairtail
no, what i mean: you're calling the cookies function in client component.
@Largehead hairtail no, what i mean: you're calling the cookies function in client component.
SiberianOP
yeah.. no. Im calling it on my server page.tsx
which is not using "use client"
Largehead hairtail
check the parent component, just like layout
server action need to be use with form, useEffect or event handler
not the page render
Largehead hairtail
if 'use client' is used in parent component like layout.tsx, your current page.tsx is client
@Largehead hairtail check the parent component, just like layout
SiberianOP
it doesnt allow me to use useEffect or useState, so I would say its not client
the best would be do it in middleware for you case
@Ray the best would be do it in middleware for you case
SiberianOP
okay, gonna try it, if not im gonna try that npm package

btw. for client-side what would be best to use instead of useEffect for function that needs to be triggered only once?
Largehead hairtail
you can use useLayoutEffect
@Siberian okay, gonna try it, if not im gonna try that npm package btw. for client-side what would be best to use instead of useEffect for function that needs to be triggered only once?
I would set the cookie on server side instead but if you really want to set it on client, then set it inside useEffect
@Siberian okay, gonna try it, if not im gonna try that npm package btw. for client-side what would be best to use instead of useEffect for function that needs to be triggered only once?
// middleware.ts
export async function middleware(request: NextRequest) {
  const uuid = request.cookies.get("uuid");
  if (uuid?.value) {
    const newExpiration = new Date();
    newExpiration.setMinutes(newExpiration.getMinutes() + 15);

    const ticketId = "";

    sql`
      UPDATE basket
      SET date = ${newExpiration.toISOString()}
      WHERE (uuid =${uuid.value}) AND (ticket_code =${ticketId})
      `;

    const res = new NextResponse();
    res.cookies.set({
      name: "uuid",
      value: uuid.value,
      expires: newExpiration,
    });
    return res;
  }
}
Answer