본문 바로가기
실무/라이브러리 및 프레임워크

vue3, Pinia

by 김홍중 2025. 3. 23.

https://github.com/HongJungKim-dev/hobby-hive

 

배포주소

https://hobby-hive-eight.vercel.app/

 

Hobby Hive - 취미 공유 커뮤니티

취미 이미지 공유 나만의 취미 활동을 이미지로 기록하고 다른 사람들과 공유해보세요. 당신의 취미 활동을 사진으로 기록하고, 다른 사람들과 함께 나눠보세요. 취미 커뮤니티에서 새로운 아

hobby-hive-eight.vercel.app

위의 프로젝트는 Next, React환경에서 만든 프로젝트이고 아래 레포에서 vue로 진행중이지만 vue로 구현한 레포는 아직 배포 및 퍼블리싱이 미비되어서 프로젝트 내용은 상단 코드와 배포주소에서 확인 가능합니다.

https://github.com/HongJungKim-dev/hobby-hive-vue

 

렌더링 매커니즘 - Vue3를 React와 비교하면서

- 렌더링 파이프라인

템플릿 → 컴파일 → 렌더 함수 → 가상 DOM 트리 → 패치 → 실제 DOM

템플릿: HTML 템플릿을 사용해 UI를 정의

컴파일: 이 템플릿이 렌더 함수로 변환. 렌더 함수는 가상 DOM 트리를 생성하는 JavaScript 코드

가상 DOM 트리 : React처럼 가상 DOM을 사용해 변경 사항을 추적.

패치 : 변경된 부분만 실제 DOM에 반영.

실제 DOM :  최종적으로 브라우저에 렌더링된 결과

 

- 마운트 및 업데이트

공통점 : 이전 상태와 새로운 상태를 비교(diffing)한 뒤 변경된 부분만 실제 DOM에 반영

Vue : 반응형 데이터(ref, reactive)를 기반으로 변경을 감지

React :상태(useState)나 props 변경에 따라 컴포넌트가 리렌더링

 

- 패치 및 최적화

Vue : 템플릿 컴파일 시점에서 정적인 부분과 동적인 부분을 미리 분석해서 불필요한 리렌더링 최소화, 컴파일 단계에서 자동 처리
React : 컴포넌트 단위로 리렌더링, React.memouseMemo 같은 최적화 도구를 사용하지 않으면 불필요한 리렌더링이 발생(useMemo와 useCallback 훅을 대체할 React Forget도 등장예정 - https://velog.io/@lky5697/how-react-forget-will-make-react-usememo-and-usecallback-hooks-absolutely-redundant)

 

React와 Vue의 주요 차이점

 

템플릿
vs JSX
- JSX로 UI를 정의
<div>{state}</div>
- <template>를 사용해 UI 정의
<div>{{ state }}</div><br>- JSX도 사용 가능
(render 함수나 JSX 활용).
상태 관리 - useState로 상태 관리
setState로 상태 업데이트 시 리렌더링 트리거.
- ref로 반응형 데이터 생성
ref 값 변경 시 자동으로 UI 갱신
반응형 시스템이 렌더링 자동 트리거.
리렌더링 - 상태나 props 변경 시 컴포넌트 리렌더링
useEffect로 부수 효과 처리
- 반응형 데이터 변경 시 가상 DOM 트리 갱신, 변경된 부분만 패치
watch 또는 computed로 부수 효과 처리

 

기본구조

<template>
  <a-modal
    :visible="isOpen"
    @update:visible="updateIsOpen"
    :width="400"
    centered
    @cancel="closeModal"
  >
    <AuthComponent />
  </a-modal>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue'
import { useRouter } from 'vue-router'
import AuthComponent from './AuthComponent.vue'

const props = defineProps({
  isOpen: {
    type: Boolean,
    required: true,
  },
})

const emit = defineEmits(['update:isOpen', 'close']) // 상태 변경 이벤트와 닫기 이벤트 정의
const router = useRouter()

const closeModal = () => {
  emit('close') // close 이벤트를 부모로 전달
  if (router.currentRoute.value.path === '/login') {
    router.back() // /login 경로인 경우 뒤로 이동
  }
}

// 부모로 상태 업데이트를 전달하는 함수
const updateIsOpen = (value) => {
  emit('update:isOpen', value) // 부모 컴포넌트로 새로운 visible 값 전달
}
</script>

 

ref

ref는 Vue 3에서 단일 값(원시 값 또는 객체)을 반응형으로 만들기 위해 사용

const loading = ref(true)
// 생략
loading.value = false

 

reactive

reactive는 객체(또는 배열)를 반응형으로 만들기 위해 사용
 

이벤트

"이벤트"는 HTML의 기본 DOM 이벤트(예: click, input, mouseover 등)가 아니라, 개발자가 컴포넌트 간 통신을 위해 정의하는 커스텀 이벤트를 의미

 

Vue에서 defineEmitsemit을 통해 다루는 이벤트는 주로 자식 컴포넌트가 부모 컴포넌트로 데이터를 전달하거나 특정 동작을 알리기 위해 사용

 

양방향 바인딩
<Child v-model="parentValue" />

 

<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps(['value']);
const emit = defineEmits(['update:value']);

const updateValue = (newValue) => emit('update:value', newValue);
</script>
<template>
  <input :value="props.value" @input="updateValue($event.target.value)" />
</template>

value prop으로 부모 → 자식 데이터 전달 (단방향)

update:value 이벤트로 자식 → 부모 데이터 전달 (단방향)

결과적으로 부모의 parentValue와 자식의 입력값이 동기화

v-model은 자식이 직접 부모의 데이터를 수정X

자식은 emit으로 이벤트를 보내고, 부모가 자신의 상태를 업데이트

 

설계 목적

  • watch:
    • Vue에서 명시적으로 특정 데이터의 변화를 감시하고, 그에 따라 정의된 콜백을 실행
    • 반응형 시스템에 특화되어 있어, 감시 대상이 변경될 때만 반응
  • useEffect:
    • React에서 렌더링 이후 부수 효과를 처리하기 위한 훅

실행시점

  • watch:
    • 감시 대상이 변경될 때마다 즉시 실행
    • immediate: true 옵션을 추가하면 처음에도 실행
    • 변경 감지에 초점이 맞춰져 있어, 값이 바뀌지 않으면 실행X
  • useEffect:
    • 렌더링이 완료된 후 실행
    • 의존성 배열이 변경되지 않으면 실행되지 않지만, 배열을 생략하면 매 렌더링마다 실행
    • 초기 렌더링에서도 기본적으로 실행

Pinia 사용 예제

 

import { defineStore } from 'pinia'

export const useModalStore = defineStore('modal', {
  state: () => ({
    isLoginModalOpen: false,
  }),
  actions: {
    openLoginModal() {
      this.isLoginModalOpen = true
    },
    closeLoginModal() {
      this.isLoginModalOpen = false
    },
  },
})

 

<LoginModal :isOpen="modalStore.isLoginModalOpen" @close="modalStore.closeLoginModal" />

 

느낀점

React를 주로 쓰다가 Vue를 사용해보니 Vue가 팀원간의 코드 일관성은 더 높을 수 있다고 생각했습니다. React가 자유도가 높은 대신에, Vue는 문법적 설탕이 있지만 템플릿화 되어있기 때문입니다.

 

다음시간에는 다음 링크를 학습해서 vue의 반응형 심화를 공부해보고자 합니다.

https://ko.vuejs.org/guide/extras/reactivity-in-depth

 

Vue.js

Vue.js - 프로그래시브 자바스트립트 프레임워크

ko.vuejs.org

 

 

참고

- Vue.js 렌더링 메커니즘 (https://ko.vuejs.org/guide/extras/rendering-mechanism#render-pipeline)

댓글