[workaround] Reference the cookie value in _document.js in Next.js
Tags: nextjs
Published: 2020-10-15 23:20:53

I wrote this post a few days ago in Japanese as well.
The post in Japanese is [here](https://zenn.dev/shinshin86/articles/82b565cb886da62556f8).

## Overview and Notes
This article describes how to reference the cookie value in `_document.js` of Next.js.
Since the code is basically written in TypeScript, the file name may be written as `_document.tsx` instead of `_document.js` from now on, but it is assumed to be the same file in both cases.

There may not be many cases where you want to refer to the cookie value in `_document.js`, But for example, there are cases where you want to control loading scripts in `<head>` tags by looking at the cookie value.
(For example, you may want to enable or disable Google Analytics.)

First of all, there are a few things to keep in mind.

First, **the way we write here is workaround**.
That's because I don't think it's a feature provided on the Next.js side.
(Because looking at the behavior of Next.js, it's hard to discern if this is a pre-expected method.)

So if you can avoid using this method, it's better.
I'm looking into it myself to see if there is a more straightforward method.

Next, I need to run the `getServerSideProps` process, which is provided in Next.js as a way to achieve what we want to achieve this time.
So if you're hosting your site as a static site on `Nelify`, for example, you can't use `getServerSideProps`, so you can't use this approach.
(I haven't checked if there is an alternative.)

### Note (About version of Next.js)
As I mentioned earlier, I'm not sure if this is what Next.js is supposed to do or not, so I'll add the possibility that the behavior may change depending on the Next.js version.

This code is verified with `version "9.5.5"`.

## Reference the cookie value in _document.js in Next.js
First, I wrote the code for verification.
If you want to see the actual behavior, clone this code locally and run it.

[Next.js sample of get cookie value at document.tsx](https://github.com/shinshin86/nextjs-sample-of-get-cookie-value-at-document)

The above code shows how to refer to the cookie value in _document.js.
* Set up the `getServerSideProps` function in the page you want to call (such as `pages/index.tsx`).
  * You don't need to write a process. -> `getServerSideProps` is written only because we want to run it once when drawing the page.
* Referencing the cookie value from `ctx.req.headers.cookie` in `_document.js`

Here's the code that actually references the cookie value in `_document.tsx`.
Here's a snippet of code from the repository above.

```tsx
export default class MyDocument extends Document<Props> {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);

    let hasCookie: boolean = false;

    if (ctx.req && ctx.req.headers.cookie) {
      console.log('cookie values: ', ctx.req.headers.cookie);
      hasCookie = true;
    }

    return { ...initialProps, hasCookie };
  }

  render() {
    console.log('hasCookie: ', this.props.hasCookie);
```

I didn't seem to have `getServerSideProps` implemented in `_document.tsx`, so I used `getInitialProps` to get the value of the cookie once.

However, even if this code actually contains the value of the cookie, it doesn't necessarily contain the value in `ctx.req.headers.cookie`.
The `getServerSideProps` call works in `pages/index.tsx`, but if you comment out this code, you won't be able to see the cookie in the above `_document.tsx`.

```diff
diff --git a/pages/index.tsx b/pages/index.tsx
index 99ea97d..23a6337 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -12,9 +12,11 @@ const IndexPage: React.FC = (): JSX.Element => (
   </div>
 );

+/*
 export async function getServerSideProps() {
   console.log('----------> Call getServerSideProps');
   return { props: {} };
 }
+*/
```

Specifically, the `ctx.req` will be `undefined`.
Apparently, only after `getServerSideProps` works, the value is stored in `ctx.req` in `_document.tsx`.

I think this code in Next.js may be helpful for this kind of behavior.
(Sorry if I got it wrong!)

https://github.com/vercel/next.js/blob/5cab03fef0782b4ecd7dbe4ec5bd10d10554650f/packages/next/next-server/server/render.tsx#L717-L728

After `getServerSideProps` runs, the values are put into `ctx.req`.
So now we need to refer to those values (in this case, `ctx.req`) on the document side after running it once on the server side.

If anyone knows of a better way to do this, please comment.

Thanks for reading!