Nuxt 를 배워보자

Nuxt.js로 메인 화면과 5개의 탭으로 구성된 블로그 예제 만들기

_Blue_Sky_ 2025. 3. 22. 22:50
728x90

 


 

 
안녕하세요, 오늘은 Nuxt.js를 활용해 메인 화면과 하위 5개의 탭으로 구성된 인터랙티브한 웹 애플리케이션을 만드는 방법을 블로그 형식으로 자세히 설명해보려고 합니다. 이 예제는 Vue.js 기반의 프레임워크인 Nuxt를 사용하며, 각 탭은 별도의 Vue 파일로 구성되어 상호작용하도록 설계됩니다. 키워드를 기반으로 한 실용적인 예제를 통해 단계별로 구현 방법을 알아보겠습니다.
목표
  • 메인 화면: 전체 레이아웃의 중심이 되는 페이지.
  • 5개의 탭: 각각 독립적인 콘텐츠를 가진 탭 (예: Home, About, Blog, Portfolio, Contact).
  • Vue 파일: 각 탭을 별도의 컴포넌트로 분리해 모듈화.
  • 상호작용: 탭 간 전환 및 데이터 공유.

1. Nuxt 프로젝트 설정
먼저 Nuxt 프로젝트를 생성합니다. 터미널에서 다음 명령어를 실행하세요:
 
 
npx create-nuxt-app tabbed-blog
설치 과정에서 기본 설정(예: Tailwind CSS, Vuex 등)을 선택할 수 있습니다. 저는 간단하게 Tailwind CSS를 추가해 스타일링을 쉽게 하겠습니다.
프로젝트 생성 후, 디렉토리로 이동해 서버를 실행합니다:
 
cd tabbed-blog
npm run dev

 
 
2. 기본 구조 설계
Nuxt에서는 pages 디렉토리에 라우팅 파일을 만들고, components 디렉토리에 재사용 가능한 컴포넌트를 작성합니다. 이번 예제에서는 메인 화면을 index.vue로 설정하고, 탭을 컴포넌트로 분리합니다.
디렉토리 구조
 
tabbed-blog/
├── pages/
│   └── index.vue         # 메인 화면
├── components/
│   ├── TabHome.vue      # 탭 1: 홈
│   ├── TabAbout.vue     # 탭 2: 소개
│   ├── TabBlog.vue      # 탭 3: 블로그
│   ├── TabPortfolio.vue # 탭 4: 포트폴리오
│   └── TabContact.vue   # 탭 5: 연락처
├── store/               # 상태 관리 (선택)
│   └── index.js
├── assets/
└── nuxt.config.js

3. 메인 화면 구현 (index.vue)
pages/index.vue는 탭 네비게이션과 선택된 탭의 콘텐츠를 표시하는 역할을 합니다.
 
<template>
  <div class="container mx-auto p-4">
    <!-- 탭 네비게이션 -->
    <div class="flex space-x-4 border-b mb-4">
      <button
        v-for="tab in tabs"
        :key="tab.name"
        @click="currentTab = tab.name"
        :class="[
          'py-2 px-4',
          currentTab === tab.name ? 'border-b-2 border-blue-500 text-blue-500' : 'text-gray-500'
        ]"
      >
        {{ tab.label }}
      </button>
    </div>

    <!-- 선택된 탭 콘텐츠 -->
    <component :is="currentTabComponent" />
  </div>
</template>

<script>
import TabHome from '~/components/TabHome.vue'
import TabAbout from '~/components/TabAbout.vue'
import TabBlog from '~/components/TabBlog.vue'
import TabPortfolio from '~/components/TabPortfolio.vue'
import TabContact from '~/components/TabContact.vue'

export default {
  components: {
    TabHome,
    TabAbout,
    TabBlog,
    TabPortfolio,
    TabContact
  },
  data() {
    return {
      currentTab: 'TabHome',
      tabs: [
        { name: 'TabHome', label: '홈' },
        { name: 'TabAbout', label: '소개' },
        { name: 'TabBlog', label: '블로그' },
        { name: 'TabPortfolio', label: '포트폴리오' },
        { name: 'TabContact', label: '연락처' }
      ]
    }
  },
  computed: {
    currentTabComponent() {
      return this.currentTab
    }
  }
}
</script>

<style scoped>
/* Tailwind CSS로 스타일링 */
</style>
  • 탭 네비게이션: 버튼 클릭 시 currentTab 값을 업데이트.
  • 동적 컴포넌트: <component :is>를 사용해 선택된 탭의 컴포넌트를 렌더링.

4. 탭 컴포넌트 구현
각 탭은 별도의 Vue 파일로 작성됩니다. 예를 들어, components/TabHome.vue:
 
 
<template>
  <div class="p-4">
    <h1 class="text-2xl font-bold">홈 탭</h1>
    <p>여기는 홈 탭입니다. 환영합니다!</p>
  </div>
</template>

<script>
export default {
  name: 'TabHome'
}
</script>
다른 탭(TabAbout.vue, TabBlog.vue 등)도 비슷하게 작성하되, 각 탭에 맞는 콘텐츠를 추가합니다.

 
5. 상태 관리 (선택 사항)
탭 간 데이터를 공유해야 한다면 Vuex를 사용해 상태를 관리할 수 있습니다. store/index.js에 다음 코드를 추가하세요:
 
 
export const state = () => ({
  activeTab: 'TabHome'
})

export const mutations = {
  setActiveTab(state, tab) {
    state.activeTab = tab
  }
}

export const actions = {
  changeTab({ commit }, tab) {
    commit('setActiveTab', tab)
  }
}
그리고 index.vue에서 상태를 반영하도록 수정:
 
 
<script>
export default {
  // ... (기존 코드)
  computed: {
    currentTab: {
      get() {
        return this.$store.state.activeTab
      },
      set(tab) {
        this.$store.dispatch('changeTab', tab)
      }
    },
    currentTabComponent() {
      return this.currentTab
    }
  }
}
</script>

6. 상호작용 추가
탭 간 상호작용 예시로, TabBlog.vue에서 버튼을 눌렀을 때 TabContact.vue로 이동하도록 해봅시다:
 
 
<!-- TabBlog.vue -->
<template>
  <div class="p-4">
    <h1 class="text-2xl font-bold">블로그 탭</h1>
    <p>여기는 블로그입니다.</p>
    <button @click="goToContact" class="bg-blue-500 text-white py-2 px-4 rounded">
      연락처로 이동
    </button>
  </div>
</template>

<script>
export default {
  name: 'TabBlog',
  methods: {
    goToContact() {
      this.$emit('change-tab', 'TabContact')
    }
  }
}
</script>
index.vue에서 이벤트를 받아 처리:
 
 
<template>
  <div class="container mx-auto p-4">
    <!-- ... -->
    <component :is="currentTabComponent" @change-tab="currentTab = $event" />
  </div>
</template>

7. 마무리
이제 Nuxt.js로 메인 화면과 5개의 탭을 가진 애플리케이션이 완성되었습니다! 반응형 웹을 위해 Tailwind CSS를 활용해 스타일을 조정하고, 필요에 따라 데이터 바인딩이나 이벤트 처리를 추가해보세요. 이 구조는 모듈화재사용성을 고려한 설계로, 확장하기도 쉽습니다.
 

 

 

Nuxt.js에서 레이아웃을 적용한 탭 기반 블로그 예제

 목표
  • 레이아웃 추가: 헤더, 사이드바, 푸터를 포함한 기본 레이아웃 설계.
  • 탭 통합: 이전 예제의 탭 구조를 레이아웃 안에 배치.
  • UI 개선: Tailwind CSS로 깔끔하고 반응형 디자인 적용.

1. 프로젝트 구조 업데이트
레이아웃을 추가하기 위해 layouts 디렉토리를 생성하고, 기본 레이아웃 파일을 만듭니다.
디렉토리 구조
 
tabbed-blog/
├── layouts/
│   └── default.vue       # 기본 레이아웃
├── pages/
│   └── index.vue         # 메인 화면 (탭 포함)
├── components/
│   ├── TabHome.vue      # 탭 1
│   ├── TabAbout.vue     # 탭 2
│   ├── TabBlog.vue      # 탭 3
│   ├── TabPortfolio.vue # 탭 4
│   └── TabContact.vue   # 탭 5
├── store/
│   └── index.js         # 상태 관리 (선택)
├── assets/
└── nuxt.config.js

2. 기본 레이아웃 설정 (default.vue)
layouts/default.vue에 헤더, 사이드바, 푸터를 포함한 레이아웃을 작성합니다. <Nuxt /> 컴포넌트는 페이지 콘텐츠(예: index.vue)가 렌더링되는 위치입니다.
 
<template>
  <div class="min-h-screen flex flex-col">
    <!-- 헤더 -->
    <header class="bg-gray-800 text-white p-4">
      <h1 class="text-2xl font-bold">Tabbed Blog</h1>
      <nav class="mt-2">
        <a href="#" class="mr-4 hover:underline">홈</a>
        <a href="#" class="mr-4 hover:underline">소개</a>
        <a href="#" class="hover:underline">연락처</a>
      </nav>
    </header>

    <!-- 메인 콘텐츠 (사이드바 + 탭 영역) -->
    <div class="flex flex-1">
      <!-- 사이드바 -->
      <aside class="w-64 bg-gray-100 p-4 hidden md:block">
        <h2 class="text-lg font-semibold">사이드바</h2>
        <ul class="mt-4">
          <li class="mb-2"><a href="#" class="text-blue-500 hover:underline">링크 1</a></li>
          <li class="mb-2"><a href="#" class="text-blue-500 hover:underline">링크 2</a></li>
          <li class="mb-2"><a href="#" class="text-blue-500 hover:underline">링크 3</a></li>
        </ul>
      </aside>

      <!-- 페이지 콘텐츠 (탭) -->
      <main class="flex-1 p-4">
        <Nuxt />
      </main>
    </div>

    <!-- 푸터 -->
    <footer class="bg-gray-800 text-white p-4 text-center">
      <p>&copy; 2025 Tabbed Blog. All rights reserved.</p>
    </footer>
  </div>
</template>

<script>
export default {
  name: 'DefaultLayout'
}
</script>

<style scoped>
/* Tailwind CSS로 반응형 스타일링 */
</style>
  • 헤더: 사이트 제목과 간단한 네비게이션.
  • 사이드바: 중형 이상 화면에서만 표시(hidden md:block).
  • 메인: <Nuxt />로 페이지 콘텐츠 렌더링.
  • 푸터: 고정된 하단 영역.

3. 메인 화면에 탭 적용 (index.vue)
이전 예제의 탭 구조를 가져와 레이아웃 안에 배치합니다.
 
<template>
  <div class="container mx-auto">
    <!-- 탭 네비게이션 -->
    <div class="flex space-x-4 border-b mb-4">
      <button
        v-for="tab in tabs"
        :key="tab.name"
        @click="currentTab = tab.name"
        :class="[
          'py-2 px-4',
          currentTab === tab.name ? 'border-b-2 border-blue-500 text-blue-500' : 'text-gray-500'
        ]"
      >
        {{ tab.label }}
      </button>
    </div>

    <!-- 선택된 탭 콘텐츠 -->
    <component :is="currentTabComponent" />
  </div>
</template>

<script>
import TabHome from '~/components/TabHome.vue'
import TabAbout from '~/components/TabAbout.vue'
import TabBlog from '~/components/TabBlog.vue'
import TabPortfolio from '~/components/TabPortfolio.vue'
import TabContact from '~/components/TabContact.vue'

export default {
  layout: 'default', // 기본 레이아웃 사용
  components: {
    TabHome,
    TabAbout,
    TabBlog,
    TabPortfolio,
    TabContact
  },
  data() {
    return {
      currentTab: 'TabHome',
      tabs: [
        { name: 'TabHome', label: '홈' },
        { name: 'TabAbout', label: '소개' },
        { name: 'TabBlog', label: '블로그' },
        { name: 'TabPortfolio', label: '포트폴리오' },
        { name: 'TabContact', label: '연락처' }
      ]
    }
  },
  computed: {
    currentTabComponent() {
      return this.currentTab
    }
  }
}
</script>
  • layout: 'default': default.vue 레이아웃을 이 페이지에 적용.

4. 탭 컴포넌트 (간단히 유지)
탭 컴포넌트는 이전과 동일하게 유지하되, 레이아웃에 맞춰 스타일을 약간 조정할 수 있습니다. 예: TabHome.vue
 
<template>
  <div class="p-4 bg-white rounded shadow">
    <h1 class="text-2xl font-bold">홈 탭</h1>
    <p>여기는 홈 탭입니다. 환영합니다!</p>
  </div>
</template>

<script>
export default {
  name: 'TabHome'
}
</script>

5. 반응형 디자인 개선
  • 사이드바: 모바일 화면에서는 숨기고, 중형 이상 화면에서 표시.
  • 탭 네비게이션: 작은 화면에서는 스크롤 가능하도록 설정 가능.
index.vue에 반응형 스타일 추가:
 
<div class="flex space-x-4 border-b mb-4 overflow-x-auto">
  <!-- 탭 버튼들 -->
</div>

6. 실행 및 확인
프로젝트를 실행해 결과를 확인합니다:
 
npm run dev
브라우저에서 http://localhost:3000에 접속하면 헤더, 사이드바, 푸터가 포함된 레이아웃 안에 5개의 탭이 동작하는 모습을 볼 수 있습니다.

 


7. 추가 아이디어
  • 상태 관리: Vuex로 탭 상태를 중앙에서 관리.
  • 애니메이션: 탭 전환 시 transition 태그로 부드러운 효과 추가.
  • 라우팅: 탭별로 URL을 연결하려면 pages에 별도 라우트를 생성.

마무리
이제 레이아웃이 적용된 Nuxt.js 탭 기반 애플리케이션이 완성되었습니다! Tailwind CSS로 반응형 디자인을 강화하고, 모듈화된 컴포넌트레이아웃 시스템을 활용해 깔끔한 UI를 구현했습니다. 
 

좋은 질문입니다! computedwatch는 Vue.js와 Nuxt.js에서 데이터 반응성을 다루는 중요한 기능인데, 각각의 용도와 장점이 다릅니다. 이번에는 질문에 맞춰 computed를 왜 사용했는지, 그리고 watch를 대안으로 사용할 수 있는지 블로그 형식으로 자세히 설명해 보겠습니다.


Nuxt.js에서 computedwatch 비교: 탭 예제에서의 선택 이유
Nuxt.js, Vue.js, 탭 네비게이션, 메인 화면, 하위 탭, 컴포넌트 상호작용, Vue 파일 구성, 상태 관리, 라우팅, 동적 탭, UI 디자인, 블로그 형식, 키워드 예제, 페이지 전환, 데이터 바인딩, 이벤트 처리, 모듈화, 프론트엔드 개발, Nuxt 프로젝트 설정, 반응형 웹, 레이아웃 설정, computed, watch, 반응형 프로퍼티

1. computed란 무엇이고 왜 사용했나?
computed는 Vue에서 계산된 속성(computed property)을 정의하는 기능입니다. 이는 데이터나 다른 속성에 의존해 값을 계산하고, 의존성이 변경될 때만 자동으로 업데이트됩니다. 캐싱(Cache)이 기본적으로 적용되어 성능 최적화에도 유리합니다.
제가 이전 예제에서 computed를 사용한 이유는 currentTabComponent를 동적으로 결정하기 위해서였습니다:
vue
 
computed: {
  currentTabComponent() {
    return this.currentTab
  }
}
  • 의존성: currentTab 값에 따라 컴포넌트 이름이 반환됩니다.
  • 단순성: currentTab이 변경되면 자동으로 새 값이 반영되며, 추가 로직 없이 바로 템플릿에 사용 가능(<component :is="currentTabComponent" />).
  • 효율성: currentTab이 변하지 않는 한 계산이 반복되지 않음(캐싱 효과).
탭 전환 시 선택된 컴포넌트를 즉시 반영해야 하므로, computed가 직관적이고 적합한 선택이었습니다.

2. watch란 무엇인가?
watch는 특정 데이터나 속성을 감시하고, 그 값이 변경될 때마다 특정 로직을 실행하는 기능입니다. 캐싱이 없고, 비동기 작업이나 복잡한 부수 효과(side effect)를 처리할 때 유용합니다.
만약 watch를 사용한다면, currentTab을 감시하고 그 값이 바뀔 때마다 컴포넌트를 업데이트하는 로직을 작성해야 합니다. 예를 들어:
vue
 
<template>
  <div>
    <component :is="activeComponent" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      currentTab: 'TabHome',
      activeComponent: 'TabHome'
    }
  },
  watch: {
    currentTab(newValue) {
      this.activeComponent = newValue
    }
  }
}
</script>
  • 동작: currentTab이 바뀔 때마다 activeComponent를 수동으로 업데이트.
  • 복잡성: 추가 데이터 속성(activeComponent)과 로직이 필요.

3. computedwatch 비교
 
특징 computed watch
용도
의존성 기반 계산 값 반환
값 변경 시 로직 실행
캐싱
있음 (의존성 변경 시만 재계산)
없음 (변경 시마다 실행)
반환값
필수 (템플릿에서 직접 사용 가능)
없음 (로직 실행에 초점)
복잡한 로직
간단한 계산에 적합
비동기 작업, 조건 처리에 유리
성능
캐싱으로 최적화
불필요한 실행 가능성 있음
탭 예제에서는 단순히 currentTab 값을 기반으로 컴포넌트를 동적으로 선택하는 작업만 필요했기 때문에, computed가 더 깔끔하고 효율적이었습니다.

4. watch로 대체 가능할까?
네, 가능합니다! 하지만 몇 가지 단점이 있습니다. 예제를 watch로 바꿔보면:
 
<template>
  <div class="container mx-auto">
    <div class="flex space-x-4 border-b mb-4">
      <button
        v-for="tab in tabs"
        :key="tab.name"
        @click="currentTab = tab.name"
        :class="['py-2 px-4', currentTab === tab.name ? 'border-b-2 border-blue-500 text-blue-500' : 'text-gray-500']"
      >
        {{ tab.label }}
      </button>
    </div>
    <component :is="activeComponent" />
  </div>
</template>

<script>
import TabHome from '~/components/TabHome.vue'
import TabAbout from '~/components/TabAbout.vue'
import TabBlog from '~/components/TabBlog.vue'
import TabPortfolio from '~/components/TabPortfolio.vue'
import TabContact from '~/components/TabContact.vue'

export default {
  components: { TabHome, TabAbout, TabBlog, TabPortfolio, TabContact },
  data() {
    return {
      currentTab: 'TabHome',
      activeComponent: 'TabHome',
      tabs: [
        { name: 'TabHome', label: '홈' },
        { name: 'TabAbout', label: '소개' },
        { name: 'TabBlog', label: '블로그' },
        { name: 'TabPortfolio', label: '포트폴리오' },
        { name: 'TabContact', label: '연락처' }
      ]
    }
  },
  watch: {
    currentTab(newValue) {
      this.activeComponent = newValue
    }
  }
}
</script>
  • 장점: watch를 사용하면 값 변경 시 추가 로직(예: 로그 출력, API 호출)을 쉽게 넣을 수 있습니다.
  • 단점: 코드가 길어지고, activeComponent라는 중간 속성이 추가되어 관리 포인트가 늘어납니다.
반면 computed는 중간 속성 없이 바로 값을 반환하므로 코드가 더 간결합니다.

5. 언제 watch를 쓰면 좋을까?
watch는 이런 상황에서 유리합니다:
  • 비동기 작업: 탭 변경 시 API를 호출해야 할 때.
     
    watch: {
      currentTab(newValue) {
        this.fetchDataForTab(newValue) // 비동기 호출
      }
    }
  • 조건 처리: 특정 탭에서만 로직을 실행하고 싶을 때.
  • 복잡한 부수 효과: 상태 변경 후 여러 변수를 업데이트해야 할 때.
탭 예제에서는 이런 복잡한 요구사항이 없었기 때문에 computed가 더 적합했습니다.

6. 결론
  • computed를 쓴 이유: 단순히 currentTab에 의존해 컴포넌트를 동적으로 선택하는 계산이 필요했고, 캐싱과 간결함이 장점이었기 때문.
  • watch도 가능하지만: 불필요한 데이터 속성과 로직이 추가되어 코드가 복잡해질 수 있음.
만약 탭 전환 시 추가 작업(예: 데이터 로딩)이 필요하다면 watch를 고려할 수 있습니다. 현재 예제의 단순한 요구사항에서는 computed가 최선의 선택입니다! 질문이 더 있다면 언제든 물어보세요!

네, 정확한 관찰이에요! watch에서 값을 바로 리턴해서 템플릿에 연결한다면, 겉보기에는 computed와 비슷한 결과를 얻을 수 있다는 점에서 혼동이 생길 수 있습니다. 하지만 이 둘은 근본적인 설계 목적과 동작 방식이 다르기 때문에, 그 차이를 명확히 이해하는 게 중요합니다. 이를 블로그 형식으로 자세히 풀어보겠습니다.


Nuxt.js 탭 예제에서 watchcomputed의 미묘한 차이: "리턴을 바로 사용하면 같지 않나?"
Nuxt.js, Vue.js, 탭 네비게이션, 메인 화면, 하위 탭, 컴포넌트 상호작용, Vue 파일 구성, 상태 관리, 라우팅, 동적 탭, UI 디자인, 블로그 형식, 키워드 예제, 페이지 전환, 데이터 바인딩, 이벤트 처리, 모듈화, 프론트엔드 개발, Nuxt 프로젝트 설정, 반응형 웹, 레이아웃 설정, computed, watch, activeComponent, 반응형 프로퍼티, 리턴값 비교

1. 질문의 핵심: "watch에서 리턴을 바로 사용하면 computed와 같지 않나?"
질문의 요지는, watch에서 감시 대상(currentTab)이 변경될 때 바로 그 값을 템플릿에 반영하면, computed처럼 동작하는 것 아니냐는 거죠. 예를 들어:
 
<template>
  <component :is="currentTab" />
</template>

<script>
export default {
  data() {
    return {
      currentTab: 'TabHome',
      tabs: [/* ... */]
    }
  },
  watch: {
    currentTab(newValue) {
      // 템플릿에서 currentTab을 바로 사용하니 여기에선 추가 작업만
      console.log(`탭 변경: ${newValue}`)
    }
  }
}
</script>
이 코드에서 <component :is="currentTab">currentTab 값에 직접 반응하니까, watch가 없어도 동작합니다. 그럼 computed와 뭐가 다를까요?

2. computedwatch의 근본적인 차이
computedwatch는 비슷해 보일 수 있지만, 설계 목적과 동작 방식이 다릅니다.
  • computed:
    • 목적: 의존성에 기반한 계산된 값을 제공.
    • 특징: 값을 반환하며, 캐싱이 적용됨. 의존성(currentTab)이 바뀌지 않으면 재계산 안 함.
    • 사용 예:
       
      computed: {
        currentTabComponent() {
          return this.currentTab // 바로 템플릿에 연결
        }
      }
    • 결과: <component :is="currentTabComponent">로 깔끔하게 사용.
  • watch:
    • 목적: 값 변경을 감지하고 부수 효과(side effect)를 실행.
    • 특징: 값을 반환하지 않음. 변경 시 로직을 수행하며, 캐싱 없음.
    • 사용 예
       
      watch: {
        currentTab(newValue) {
          // 추가 작업 (예: 로그, API 호출)
          console.log(newValue)
        }
      }
    • 결과: 템플릿에 반영하려면 별도의 데이터 속성(예: activeComponent) 필요하거나, currentTab을 직접 사용.

3. "watch에서 리턴을 바로 사용한다"는 오해
사실 watch는 값을 "리턴"하지 않습니다. watch핸들러 함수일 뿐이라, 실행 결과로 템플릿에 직접 연결할 수 없습니다. 질문에서 "리턴을 바로 사용한다"는 표현은 아마도 watch가 감시하는 값(currentTab)을 템플릿에서 바로 쓰는 상황을 의미한 것 같아요.
예를 들어:
 
<template>
  <component :is="currentTab" />
</template>

<script>
export default {
  data() {
    return {
      currentTab: 'TabHome'
    }
  },
  watch: {
    currentTab(newValue) {
      // 여기서 뭔가를 "리턴"해도 템플릿에 반영 안 됨
      return newValue // 무의미
    }
  }
}
</script>
  • watchreturn은 아무 효과 없음. 템플릿은 이미 currentTab에 반응하니까 watch가 없어도 동작.
  • 이 경우 computed처럼 보이지만, computed는 명시적으로 계산된 값을 제공한다는 점에서 다름.

4. watchcomputed처럼 쓰려면?
watch를 강제로 computed처럼 흉내 내려면, 별도의 데이터 속성을 만들어 값을 저장해야 합니다:
 
<template>
  <component :is="activeComponent" />
</template>

<script>
export default {
  data() {
    return {
      currentTab: 'TabHome',
      activeComponent: 'TabHome' // 중간 속성
    }
  },
  watch: {
    currentTab(newValue) {
      this.activeComponent = newValue // 수동으로 연결
    }
  }
}
</script>
이건 computed와 비슷한 결과를 내지만:
  • 비효율적: 캐싱 없음, 불필요한 속성 추가.
  • 복잡성: 코드가 길어짐.
반면 computed는:
computed: {
  currentTabComponent() {
    return this.currentTab
  }
}
  • 간결하고, 캐싱으로 최적화됨.

5. 진짜 차이는 언제 드러나나?
watchcomputed의 차이는 단순 값 반영이 아니라 추가 로직이 필요할 때 명확해집니다.
  • computed로 어려운 경우:
    computed: {
      currentTabComponent() {
        // 비동기 작업 불가
        fetchData(this.currentTab) // 안 됨
        return this.currentTab
      }
    }
  • watch가 빛나는 경우:
    watch: {
      currentTab(newValue) {
        // 비동기 작업 가능
        this.fetchData(newValue).then(() => {
          console.log('데이터 로드 완료')
        })
      }
    }
탭 예제에서 단순히 컴포넌트를 바꾸는 데만 집중했기 때문에 computed가 충분했지만, 탭 변경 시 API 호출이나 복잡한 로직이 필요하면 watch가 더 유리합니다.

6. 결론: 같아 보이지만 다르다
  • **watch에서 "리턴을 바로 사용"**한다는 건, watch가 아니라 템플릿이 currentTab에 직접 반응하는 상황을 의미. 이 경우 computed와 겉보기 결과는 비슷할 수 있음.
  • 차이점:
    • computed: 계산된 값을 제공, 캐싱으로 효율적, 단순 값 반영에 최적.
    • watch: 변경 감지 후 로직 실행, 부수 효과 처리에 유리, 값 자체를 템플릿에 연결하려면 추가 작업 필요.
결국 질문의 상황(탭 컴포넌트 동적 변경)에서는 computed가 더 자연스럽고, watch는 추가 로직이 필요할 때 쓰는 게 맞습니다. 혼동이 풀렸기를 바랍니다! 더 궁금한 점 있으면 언제든 물어보세요!
728x90