Store state in cookies with use-cookie-state React hook
Tags: react, hook, cookies, nextjs
Published: 2020-10-28 17:24:54

🤔 Sometimes it becomes necessary to keep the state of the application between reloads of the web page.
The most common use for this is `localStorage`.

When developing an application on `Next.js`, I needed to receive this data during page rendering on the server-side(SSR), `localStorage` is not suitable for this purpose, so I decided to use `cookies`.

>☝️ A cookie can contain data upto a maximum of 4096 Bytes. If you want to support most browsers, then do not exceed 50 cookies per domain, and 4093 bytes per domain. The size of all cookies together should not exceed 4096 bytes.

>🐜 Therefore, this solution is well suited for storing small data such as `language` or `theme`.

When opening a web application page, `cookies` are sent to the server along with `Http` request, then I can get their value and use it in SSR.


> To work with cookies, I decided to use an existing solution,
choosing the most popular [cookies](https://www.npmjs.com/package/cookies) library for reading and writing cookie values.

👏 First, let's create a helper function, to read and write cookie values - `getCookieValue`

```javascript
import cookie from "cookie";

function getCookieValue({
  key,
  cookies,
  options,
  defaultValue,
} {
  const value = cookie.parse(cookies || "", options);

  return value[key] ?? defaultValue;
}
```
⚙️ Function arguments:

- key - _a unique key with which our value will be stored in browser cookies_
- cookies - _the cookies themselves_
- options - _`cookie` [parse options](https://www.npmjs.com/package/cookie#options) from [cookies](https://www.npmjs.com/package/cookies) library_
- defaultValue - _default value, in case a value was not found for the specified key_


ℹ️ If you are not familiar with `??` operator, don't worry.
It's called `nullish coalescing operator` and is similar to `||` but only returns the right side when the left side is `null` or `undefined`. You can read more about this [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator)

The matter is small; it remains to implement the React Hook itself

```javascript
function useCookieState(
  key,
  initialValue,
  options
) {
  const getInitialValue = () => {
    // if we on the server just use an initial value
    if (typeof window === "undefined") return initialValue;

    // otherwise get initial cookie value from `document.cookies`
    return getCookieValue({
      key,
      cookies: document.cookie,
      options: options?.decodeOps,
      defaultValue: initialValue,
    });
  };

  // get initial state value on component mounts
  const [value, setValue] = useState(getInitialValue); 

  // encode and save the new cookie value
  const setNextValue = (value) => {
    document.cookie = cookie.serialize(key, value, options?.encodeOps);
    setValue(value);
  };

  return [value, setNextValue];
}
```

⚙️ Here we have a hook with three arguments:

- key - _the same as in the previous function_
- initialValue - _the initial value for the state, the same as the default value_
- options - _an object with shape:_
  - decodeOps - _[parse cookies](https://www.npmjs.com/package/cookie#options) parameters_
  - encodeOps - _[serialize cookies](https://www.npmjs.com/package/cookie#options-1) parameters_

ℹ️ As you can see, there is another `?.` operator here, called the ʻoptional chaining operator`.
It avoids errors like ʻUncaught TypeError: Cannot read property 'prop_name' of undefined`, returning simply ʻundefined` in this case, you can read more about it [here] (https://developer.mozilla.org/en-US / docs / Web / JavaScript / Reference / Operators / Nullish_coalescing_operator)

🎆 That's all! 🎆

Oh yeah, I almost forgot. 
For your convenience, I put the hook in a tiny library, with TypeScript support, enjoy! ✨

😊 Thank you for your attention!

🍪 https://github.com/dqunbp/use-cookie-state 🍪