반응형
| Options API | Composition API (vue3) | ||
| ref reactive |
export default { name:'', // 컴포넌트 이름 components:{}, // 자식 컴포넌트 등록 props:{}, // 부모로부터 받는 속성 emits:[], // 자식 → 부모 이벤트 data(){return{};}, // 반응형 데이터 computed:{}, // 계산된 속성 watch:{}, // 감시자 methods:{}, // 메서드 정의 provide(){return{};}, // 하위 컴포넌트 제공 inject:[], // 상위 컴포넌트에서 주입 mixins:[], // 믹스인 extends:{}, // 확장할 컴포넌트 created(){}, // 생성 시 mounted(){} // 마운트 시 }; |
<script> import {ref, reactive, comupted } from "vue"; export default{ const count = ref(0); //RefImpl 형태 value로접근이유 console.log(count); const increment = comupted(()=>{ return `count: ${count.value}`++; }); setup(){ return{ // 객체로 반환해야 정상사용 count, increment, message }; } }; </script> <template> <h1>{{message}}</h1> <button @click="increament">증가 </button> </template> |
ref : 기본자료형 reactive : 참조자료형 |
| watch | export default { data() { return { user: { name: '홍길동' } }; }, watch: { user: { handler(newVal, oldVal) { console.log('깊은:', newVal.name); }, deep: true, immediate: true } } }; |
<script setup> import { reactive, watch } from 'vue'; const user = reactive({ name: '홍길동' }); console.log( user ) //proxy 객체 watch( user, (newVal, oldVal) => { console.log('깊은', newVal.name); }, { deep: true } ); or watch( ()=>user.value.name, (newVal, oldVal) => { console.log('깊은', newVal.name); }, { deep: false, immediate: true } ); </script> |
객체 내부 속성 변화를 감지 1. deep: true 깊은 감시여부 선택가능 2. immediate: true 감지여부 상관없이 처음 무조건 실행 3. flush 옵션 pre : Dom 업데이트이전, 기본 post :Dom 업데이트 이후 , css 적용시 고려 sync : 반응형상태 변경과 동시 4. 배열로 지정가능 const x = ref(0); const y = ref(0); const z = ref(0); watch( [x, y, z], (newVal, oldVal) => { }); 감시대상이 감지안되면 callback 함수 호출안함 * getter함수 : ()=>user.value.name |
| watchEffect() | 없음 | import { ref, watchEffect } from 'vue'; const message = ref('안녕'); watchEffect(() => { console.log(user.value.name); # name 만 추적 }); |
watchEffect() 안에서 사용된 반응형 변수들을 Vue가 자동으로 추적 1. 즉시실행 2. 자동추적 3. 사용된 값만 추적 4. 각각 의 값을 추적할때 공통된 콜백함수 실행 5. flush 옵션 pre : Dom 업데이트이전 post :Dom 업데이트 이후 , css 적용시 고려 sync : 반응형상태 변경과 동시 |
| watchposteffect() | watchPostEffect(() => { if (box.value) { console.log('렌더링 후 박스 높이:', box.value.offsetHeight); } }); |
watchEffect() 와 비슷하지만 DOM 업데이트 이후 실행, offsetHeight, scrollTop, focus 같은 css 요소 읽을때 유리 |
|
| watch 해지 | var unwatch = watch() var unwatch = watchEffect () var unwatch = watchposteffect() unwatch() // 해지 |
| 컴포저블 패턴 | Vue Composition API(vue3)를 이용해 반복되는 로직을 재사용 가능한 함수로 분리하는 방식 setup() 안에 자주 쓰는 ref, watch, api 호출, 유효성 검사, 토스트 알림 등등을 밖으로 빼서 따로 함수화해두고, 필요한 컴포넌트에서 불러다 재사용하는 패턴 |
||
| 상태 비저장 로직 | 어떤 입력에 따른 결과값을 즉시 반환 ex) 날짜 포멧팅 |
||
| 상태 저장 로직 | 마우스포인터위치 composables/useMouse.js -------------------------------- import { ref, onMounted, onUnmounted } from 'vue' export function useMouse() { const x = ref(0) const y = ref(0) function updateMouse(e) { x.value = e.pageX y.value = e.pageY } onMounted(() => { window.addEventListener('mousemove', updateMouse) }) onUnmounted(() => { window.removeEventListener('mousemove', updateMouse) }) return { x, y } } components/MouseTracker.vue ----------------------------- <script setup> import { useMouse } from '@/composables/useMouse' const { x, y } = useMouse() </script> <template> <p>마우스 위치: X = {{ x }}, Y = {{ y }}</p> </template> |
시간이 지나면서 변경되는 상태를 다루는 로직 - 반응형 localStorage 구현시 새로고침때유지 확인가능 |
|
| 상태 저장및 비동기 ( axios 사용 ) |
// plugins/api.js import axios from 'axios' const api = axios.create({ baseURL: 'https://example.com/api', headers: { 'Content-Type': 'application/json' } }) export default api // composables/useAxios.js import { ref } from 'vue' import api from '@/plugins/api' // Axios 인스턴스 import export function useAxios() { const data = ref(null) const error = ref(null) const loading = ref(false) const request = async (config) => { loading.value = true error.value = null try { const res = await api.request(config) data.value = res.data } catch (err) { error.value = err } finally { loading.value = false } } return { data, error, loading, request } } <script setup> import { onMounted } from 'vue' import { useAxios } from '@/composables/useAxios' const { data, error, loading, request } = useAxios() onMounted(() => { request({ method: 'get', url: '/posts' }) }) </script> <template> <div v-if="loading">로딩 중...</div> <div v-else-if="error">에러: {{ error.message }}</div> <ul v-else> <li v-for="item in data" :key="item.id">{{ item.title }}</li> </ul> </template> |
try { const res = await api.request(config) data.value = res.data } catch (err) { error.value = err } finally { loading.value = false } } 는 api.request(config) .then(res => { data.value = res.data }) .catch(err => { error.value = err }) .finally(() => { loading.value = false }) 으로 구현가능 watchEffect(()=>{ request(); }) 결과값을 watch 로 변경된값을 받아야함. |
|
| pinia 사용 | // stores/post.js import { defineStore } from 'pinia' import { ref } from 'vue' import api from '@/plugins/api' export const usePostStore = defineStore('post', () => { const posts = ref([]) const loading = ref(false) const error = ref(null) const fetchPosts = async () => { loading.value = true error.value = null try { const res = await api.get('/posts') posts.value = res.data } catch (err) { error.value = err } finally { loading.value = false } } return { posts, loading, error, fetchPosts } }) <script setup> import { onMounted } from 'vue' import { usePostStore } from '@/stores/post' const postStore = usePostStore() onMounted(() => { postStore.fetchPosts() }) </script> <template> <div v-if="postStore.loading">로딩 중...</div> <div v-else-if="postStore.error">에러: {{ postStore.error.message }}</div> <ul v-else> <li v-for="post in postStore.posts" :key="post.id">{{ post.title }}</li> </ul> </template> |
||
'Web' 카테고리의 다른 글
| [핵심만 골라 배우는 Vue.js by 수코딩] 10. 피니아(Pinia), storeToRefs (6) | 2025.08.05 |
|---|---|
| [핵심만 골라 배우는 Vue.js by 수코딩] 9. 라우팅 (1) | 2025.08.05 |
| [핵심만 골라 배우는 Vue.js by 수코딩] 7. 컴포넌트 심화- 상속, 동적렌더링 (1) | 2025.08.04 |
| [핵심만 골라 배우는 Vue.js by 수코딩] 6. 컴포넌트 기본- 스타일, 템플릿, 렌더함수 (0) | 2025.08.01 |
| [핵심만 골라 배우는 Vue.js by 수코딩] 5. 라이프사이클 훅 (1) | 2025.08.01 |