Files
gil-wiki/wiki/nuxt-state-management.md
gil 5f664546cf feat: 위키 저장소 초기 커밋
- CLAUDE.md 운영 규칙
- wiki/ 정리된 지식 페이지 (Nuxt + Claude Code)
- raw/ 원본 자료
- reference/ Nuxt 4.x 공식 문서

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 00:31:51 +09:00

3.6 KiB

Nuxt 상태 관리

카테고리: 핵심 개념 최종 수정: 2026-05-13 관련: nuxt-data-fetching, nuxt-lifecycle

요약

useState는 Nuxt 내장 SSR-친화적 전역 상태다. 컴포넌트 간 key로 상태를 공유하고, 서버에서 설정한 값이 하이드레이션 후 클라이언트에서도 유지된다. 더 복잡한 상태는 Pinia 모듈을 쓴다.


useState

SSR-friendly ref 대체제. 같은 key를 쓰는 컴포넌트가 동일한 반응형 상태를 공유.

// 기본 사용
const counter = useState('counter', () => 0)

// 타입 지정
const user = useState<User | null>('user', () => null)

⚠️ 주의: <script setup> 또는 setup() 외부에서 const state = ref()를 절대 정의하지 말 것. 서버에서 요청 간 상태가 공유되어 메모리 누수 발생.

// ❌ 잘못된 패턴 — 서버에서 요청 간 공유됨
export const myState = ref({})

// ✅ 올바른 패턴
export const useMyState = () => useState('myState', () => ({}))

비동기 초기화

앱 시작 시 서버에서 한 번 데이터를 가져와 상태를 초기화할 때 callOnce 사용:

<!-- app/app.vue -->
<script setup lang="ts">
const websiteConfig = useState('config')

await callOnce(async () => {
  websiteConfig.value = await $fetch('https://my-cms.com/api/website-config')
})
</script>

callOnce는 서버에서 1회, 클라이언트 하이드레이션 시 재실행하지 않음 (Nuxt 2의 nuxtServerInit과 유사).


컴포저블로 공유 상태 패턴

타입-안전한 전역 상태를 컴포저블로 캡슐화:

// composables/states.ts
export const useColor = () => useState<string>('color', () => 'pink')
export const useUser = () => useState<User | null>('user', () => null)
<script setup lang="ts">
const color = useColor()  // useState('color')와 동일
</script>

고급 패턴: SSR-친화적 로케일

// composables/locale.ts
export const useLocale = () => useState<string>('locale', () => useDefaultLocale().value)

export const useDefaultLocale = (fallback = 'en-US') => {
  const locale = ref(fallback)
  if (import.meta.server) {
    const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0]
    if (reqLocale) locale.value = reqLocale
  } else if (import.meta.client) {
    const navLang = navigator.language
    if (navLang) locale.value = navLang
  }
  return locale
}

Pinia 통합

복잡한 상태, 액션, 게터가 필요할 때 Pinia 사용.

npx nuxt module add pinia
// app/stores/website.ts
export const useWebsiteStore = defineStore('websiteStore', {
  state: () => ({
    name: '',
    description: '',
  }),
  actions: {
    async fetch() {
      const infos = await $fetch('https://api.nuxt.com/modules/pinia')
      this.name = infos.name
      this.description = infos.description
    },
  },
})
<!-- app/app.vue -->
<script setup lang="ts">
const website = useWebsiteStore()
await callOnce(website.fetch)  // 서버에서 1회 실행
</script>

useState vs Pinia 선택 기준

useState Pinia
복잡도 단순 복잡한 상태·액션
타입 안전성 기본 풍부한 타입 지원
DevTools (Vue DevTools 통합)
설치 내장 모듈 설치 필요
사용 시점 간단한 공유 상태 스토어 패턴 필요 시

상태 유틸

유틸 용도
clearNuxtState(key?) 특정 key 또는 전체 상태 초기화

참고 / 출처

  • reference/1.getting-started/11.state-management.md