๐ŸŠ ๋‚‘๊นกํŒœ_08 : "localStorage is not defined" in Next.js with js-cookie

Boriยท2022๋…„ 2์›” 19์ผ
14

Project_Kkingkkang.farm

๋ชฉ๋ก ๋ณด๊ธฐ
8/9
post-thumbnail
post-custom-banner

์ง„ํ–‰ ์ƒํ™ฉ

list-followers.tsx

  • js-cookie ์„ค์น˜
  • Cookie์— ์ €์žฅ๋œ accountname, token ์ด์šฉ
  • follower list API ์—ฐ๋™

๐Ÿ”ธ How to Fix "localStorage is not defined" in Next.js

Next.js์—์„œ localStorage๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค.

ReferenceError: localStorage is not defined

์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ 

  • Next.js๋Š” client-side๋ฅผ ๋ Œ๋”ํ•˜๊ธฐ ์ „ server-side ๋ Œ๋”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • Next.js์—์„œ ์ œ๊ณตํ•˜๋Š” Server Side Rendering(SSR)์—์„œ๋Š” window, document ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ € ์ „์—ญ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
  • window ๊ฐ์ฒด๋Š” client-side์—๋งŒ ์กด์žฌํ•œ๋‹ค.

=> ๋”ฐ๋ผ์„œ, ํŽ˜์ด์ง€๊ฐ€ client์— ๋กœ๋“œ๋˜๊ณ  window ๊ฐ์ฒด๊ฐ€ ์ •์˜๋  ๋•Œ๊นŒ์ง€ localStorage์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

typeof window !== 'undefined'

  • ํŽ˜์ด์ง€๊ฐ€ client์— ๋งˆ์šดํŠธ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ localStorage ์ ‘๊ทผํ•ด์•ผํ•œ๋‹ค.
  • window ๊ฐ์ฒด๊ฐ€ ์ฐธ์กฐ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, undefined๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • localStorage ์— ์ ‘๊ทผํ•˜๊ธฐ ์ „์— localStorage ๊ฐ€ ์ •์˜๋œ๋‹ค.
if (typeof window !== 'undefined') {
  // Perform localStorage action
  const item = localStorage.getItem('key');
}

useEffect

  • useEffect๋Š” ๋ Œ๋”๋ง ์‹œ ์‹คํ–‰๋˜๋ฏ€๋กœ, ์ดˆ๊ธฐ ์„œ๋ฒ„ ๋นŒ๋“œ ์‹œ useEffect ๋‚ด๋ถ€ ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Œ
  • useEffect ๋Š” client side์—์„œ๋งŒ ์‹คํ–‰๋˜๋ฏ€๋กœ localStorage์— ์•ˆ์ „ํ•˜๊ฒŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
import { useEffect } from "react";

useEffect(() => {
  // Perform localStorage action
  const item = localStorage.getItem('key')
}, [])

์ฐธ๊ณ ๋งํฌ

  • ์ฟ ํ‚ค๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฟ ํ‚ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๐Ÿ”ธ ์„ค์น˜

npm i js-cookie
# yarn์œผ๋กœ ์„ค์น˜ํ•  ๊ฒฝ์šฐ
yarn add js-cookie

TypeScript declarations

  • TypeScript ์‚ฌ์šฉ์‹œ ํƒ€์ž…์„ ์–ธ ํŒจํ‚ค์ง€๋„ ์„ค์น˜
npm install --save @types/js-cookie
# yarn์œผ๋กœ ์„ค์น˜ํ•  ๊ฒฝ์šฐ
yarn add @types/js-cookie

ES Module

  • ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ES ๋ชจ๋“ˆ์„ import ํ•˜๋Š” ๋ฐฉ๋ฒ•
import Cookies from 'js-cookie'

Cookies.set('foo', 'bar')

ES Module

  • ES6์— ๋„์ž…๋œ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ
  • import, export๋ฅผ ์‚ฌ์šฉํ•ด ๋ถ„๋ฆฌ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ๋ผ๋ฆฌ ์„œ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฐธ๊ณ ๋งํฌ: ES Modules ์ •๋ฆฌํ•˜๊ธฐ

    => ES Module ๋‚ด์šฉ ์ •๋ฆฌํ•˜๊ธฐ

์‚ฌ์šฉ๋ฒ•

  • ์ฟ ํ‚ค ๊ตฝ๊ธฐ
// ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
Cookies.set('name', 'value')

// ๋งŒ๋ฃŒ ๊ธฐ๊ฐ„ ์„ค์ •: ์ง€๊ธˆ๋ถ€ํ„ฐ 7์ผ ํ›„ ๋งŒ๋ฃŒ
Cookies.set('name', 'value', { expires: 7 })
  • ๊ตฌ์šด ์ฟ ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ
Cookies.get('name') // => 'value'
Cookies.get('nothing') // => undefined

// ๋ชจ๋“  ์ฟ ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ
Cookies.get() // => { name: 'value' }
  • ๊ตฌ์šด ์ฟ ํ‚ค ์‚ญ์ œ
Cookies.remove('name')

expires

  • ์ฟ ํ‚ค ๋งŒ๋ฃŒ ๊ธฐ๊ฐ„์„ ์ •์˜
  • ์ƒ๋žตํ•˜๋ฉด ์ฟ ํ‚ค๊ฐ€ ์„ธ์…˜ ์ฟ ํ‚ค๊ฐ€ ๋œ๋‹ค.
  • Default : ์ฟ ํ‚ค๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ซ์„ ๋•Œ ์ œ๊ฑฐ๋œ๋‹ค.
Cookies.set('name', 'value', { secure: true })
Cookies.get('name') // => 'value'
Cookies.remove('name')

๐Ÿ”ธ ์ด๋ฉ”์ผ๋กœ ๋กœ๊ทธ์ธํ•˜๋Š” ํŽ˜์ด์ง€ ์ฝ”๋“œ

  • ๊ธฐ์กด localStorage์—์„œ Cookie๋กœ ๋ณ€๊ฒฝ
  const router = useRouter();
  // ์ €์žฅ๋œ token์ด ์žˆ์„ ๊ฒฝ์šฐ (๋กœ๊ทธ์ธ ์ƒํƒœ์ธ ๊ฒฝ์šฐ)
  if (Cookies.get('token')) {
    // ํ™ˆ์œผ๋กœ ์ด๋™
    router.push('/home');
  }

  // submit button ํด๋ฆญ
  const onSubmit = handleSubmit(async (userData) => {
    const { data } = await axios(`${API_ENDPOINT}/user/login`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: JSON.stringify({
        user: {
          email: userData.email,
          password: userData.password,
        },
      }),
    });

    // error message๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ,
    if (data.message) {
      // ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
      setLoginError('์ด๋ฉ”์ผ ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.');
    } else {
      // ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ ์œ ์ €์˜ accountname, token์„ ์ฟ ํ‚ค์— ์ €์žฅ
      Cookies.set('accountname', data.user.accountname);
      Cookies.set('token', data.user.token);
    }
  });
post-custom-banner

5๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2022๋…„ 2์›” 22์ผ

์—ด์‹ฌํžˆ ํ”„๋กœ์ ํŠธ ํ•˜์‹œ๋Š” ๋ณด๋ฆฌ๋‹˜๐ŸŠ
๋ฉ‹์žˆ์–ด์š”! ํ™”์ดํƒฑ~!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2022๋…„ 3์›” 1์ผ

์—ฌ๊ธฐ๊ฐ€ ์ฟ ํ‚ค ๋ง›์ง‘์ธ๊ฐ€์š”??

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2022๋…„ 7์›” 29์ผ

๋ณด๋ฆฌ๋‹˜ ์ž˜๋ดค์Šต๋‹ˆ๋‹ค ใ…Žใ…Ž

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ