2

I implemented a program with next js , i want to use cookies on dynamic pages , the problem is that the cookie value is inherited in other pages , this happens while each page should have its own cookie.

I want to have a button to set cookie and a Link for navigation between dynamic blog routes , when i set the cookie for example in this path /blog/2 and then i refresh the page to see the cookie in the current page and click on the Link to go to next blog or previous blog , the cookie is inherited in other dynamic blog routes.

  • In this example , the js-cookie module is used.

Example :

// /blog/[blogId]

import Cookies from 'js-cookie';
import Link from 'next/link';
import { useRouter } from 'next/router';
import dynamic from 'next/dynamic';

function SingleBlog() {
    const router = useRouter();
    const { blogId } = router.query;

    return (
        <>
            <Link href={`/blog/${Number(blogId) + 1}`}> next blog </Link>
            <button onClick={() => Cookies.set('name', `blog${blogId}`, { path: `/blog/${blogId}` })}> set </button>
            {Cookies.get('name') && <p>cookie : {Cookies.get('name')}</p>}
        </>
    )
}

export default dynamic(() => Promise.resolve(SingleBlog), { ssr: false });

  • If the page is refreshed, we see the cookie value and if the navigation between the blog pages is inside the program, the cookie value that is displayed is a fixed value in any case.

What is the solution ?

1 Answers1

0

UPDATE

Upon further investigation, I was able to determine that browsers do NOT refresh document.cookie with path-specific cookies after client-side navigation. Here is a minimal reproducible example:

// pages/blog/[blog].tsx

import * as React from "react";
import Link from "next/link";
import { useRouter } from "next/router";

export default function Page() {
  const router = useRouter();
  const path = router.asPath;
  const blog = router.query.blog;

  const [cookies, setCookies] = React.useState("");

  const refreshCookie = React.useCallback(() => {
    // ignore initial render
    if (blog !== undefined) {
      console.log(window.location.href, document.cookie);
      setCookies(document.cookie);
    }
  }, [blog]);

  React.useEffect(refreshCookie, [refreshCookie]);

  const saveCookie = () => {
    document.cookie = `cookie=${path}; path=${path}; max-age=${30 * 24 * 3600}`;

    refreshCookie();
  };

  if (blog === undefined) return null;

  return (
    <>
      <nav>
        <Link href="/blog/1">Blog 1</Link>
        <Link href="/blog/2">Blog 2</Link>
        <Link href="/blog/3">Blog 3</Link>
      </nav>

      <h1>Blog {blog}</h1>

      <p>document.cookie: {cookies}</p>

      <button type="button" onClick={saveCookie}>
        Set cookie
      </button>
    </>
  );
}

Sandbox - https://codesandbox.io/p/sandbox/stackoverflow-76316769-wlutfv?file=%2Fpages%2Fblog%2F%5Bblog%5D.tsx

I do not have a good explanation of this behavior at this point. However, I can suggest several alternative solutions.

1) Read cookies server-side on each request

This can be implemented either with getServerSideProps under the Pages Router, or with cookies function under the App Router.

Here is an example using the App Router - https://codesandbox.io/p/sandbox/stackoverflow-76316769-app-ocw66i?file=%2Fapp%2Fblog%2F%5Bblog%5D%2FBlog.tsx

2) Fetch cookies client-side from an API route

Here is an example using the App Router - https://codesandbox.io/p/sandbox/stackoverflow-76316769-app-route-y4jcgw?file=%2Fapp%2Fblog%2F%5Bblog%5D%2FBlog.tsx

I hope this helps.


Original answer

(the original answer addressed an obvious issue in the initial OP's code)

The value that you pass as an argument to useState is used only one time during the initial render to determine the initial state. If you want to use an updated cookie value every time props.blog slug changes, you should read cookie value in useEffect and update your state accordingly.

Igor Danchenko
  • 1,980
  • 1
  • 3
  • 13
  • The problem is that the cookie is not received from the current path, the last value that is set is inherited in all pages. – Pouriya Sedaghat May 25 '23 at 14:39
  • if the page is refreshed, it will receive the correct cookie value – Pouriya Sedaghat May 25 '23 at 14:59
  • Are you using `app` or `pages` directory? – Igor Danchenko May 25 '23 at 15:05
  • In the `cookie.set` option , I use a dynamic path with the path value of each page , It means that we have exclusive access to that cookie in a dynamic page , for sample in the `localehost:3000/blog/10` i have a exclusive cookie and ... , the path value in the option is the same as for dynamic route pages – Pouriya Sedaghat May 25 '23 at 15:32
  • I've updated my answer with minimal reproducible example, and suggested 2 alternative solutions. Please let me know if you need the examples for Pages Router. – Igor Danchenko May 26 '23 at 16:41
  • I'd also recommend you update your question with just one code snippet reproducing the issue because right now it's kind of hard to follow. Please feel free to use the minimal repro that I posted above. Hopefully, somebody else from the community will be able to chime in on this issue. – Igor Danchenko May 26 '23 at 16:44
  • The things you said were already done and the problem was not solved, I optimized the question. – Pouriya Sedaghat May 27 '23 at 22:13