1. props를 인자로 넘기면 반응성을 잃는다?
vue
에서는 컴포저블을 사용하여 비즈니스 로직을 분리할 수 있다.- 또한, 컴포저블의 인자로 반응형 변수를 전달할 수도 있다.
- 그러나, 반응형 변수를 컴포저블 인자로 전달하면 반응성을 잃는 경우가 발생한다.
- 아래 코드는 사용자 데이터를 관리하는
useUser
컴포저블이다. - 이 컴포저블은
id
값을 인자로 받아서,id
값이 변경될 때 어떤 처리를 한다.
export function useUser(id) {
watch(id, () => {
// 어떤 처리
});
}
computed
나ref
,reactive
로 선언된 변수를 컴포저블의 인자로 전달하면, 인자는 반응성을 유지한다.
const userId = computed(() => ...)
useUser(userId); // this!
- 그런데!
props
변수를 인자로 넘기면, 해당 인자는 반응성을 잃게 된다!
const props = defineProps({
userId: {
type: Number,
required: true
}
})
useUser(props.userId); // this!
❓
props
는 분명히 반응형 변수인데,props
를 컴포저블의 인자로 전달하면 왜 반응성을 잃게 되는 걸까?
- 그 이유는
props
의 값 접근 방식 때문이다! - 이번 시간에는
props
변수의 특징과 함께,props
의 반응성을 유지하는 두 가지 방법을 알아본다.
2. props의 반응성을 유지하는 법
1) props의 값 접근 방식이 반응성을 잃게 한다?
- Vue에서 반응형 변수를 다루는 방법으로는
prop
,ref
,reactive
,computed
이 있다. ref
,reactive
,computed
는.value
형태로 값에 접근할 수 있다.- 또한,
.value
대신, 변수 자체를 호출하면 반응형 객체에 접근할 수 있다.
const data1 = ref('안녕');
const data2 = reactive({ id: 1 });
const data3 = computed(() => 'hello');
// 값 접근 방법 ✅
console.log(data1.value); // 안녕
console.log(data2.value); // { id: 1 }
console.log(data3.value); // hello
// 반응형 객체 접근 ✅
console.log(data1);
console.log(data2);
console.log(data3);
- 아래 이미지는 반응형 객체의 예시이다.
- 그에 비해 props는 props.XXX 형태로 값에 접근해야 한다.
- 앞선 예시처럼, 변수 자체를 호출해도 반응형 객체에 접근할 수 없다.
const props = defineProps({
data: {
type: Number,
required: true
}
})
// 값 접근 방법 ✅
console.log(props.data);
// 반응형 객체 접근 ❌
console.log(props.data);
props
는 변수 자체를 호출하면, 반응형 객체가 아닌 값에 접근한다.- 이러한 이유로, 컴포저블에
props
변수를 인자로 전달하면, 인자가 반응성을 잃게 된다.
2) props의 반응성을 지키는 두 가지 방법
📌 그럼
props
변수를 컴포저블의 인자로 전달할 때, 반응성을 유지할 방법은 없을까?
두 가지 방법이 있다! 하나는 getter 함수를 사용하는 것이고, 다른 하나는 toRef()를 사용하는 것이다.
(1) props를 getter 함수로 선언하기
watch
에서props
를 감시하고 싶을 때,props
를 어떻게 전달해야할까?- 바로 "props 값을 반환하는 getter 함수" 형태로 전달하는 것이다!
props
를 getter함수 방식으로 선언하면, 반응형 변수처럼 사용할 수 있다.
watch(
() => props.data, // this!
() => { ... }
)
- 이 getter 함수 방식은 컴포저블에
props
를 인자로 전달할 때 사용할 수 있다. - getter 함수 형태로
props
값을 넘기면, 우리가 의도한 대로 값의 반응성을 유지할 수 있다.
const props = defineProps({
userId: {
type: Number,
required: true
}
})
useUser(() => props.userId); // this!
(2) toRef 사용하기
- 두 번째는
toRef()
를 사용하는 방법이다. - 공식문서에서
toRef()
설명을 보면, “컴포저블에 prop를 인자로 넘길 때 toRef()를 사용하면 반응성을 지킬 수 있다“고 되어 있다.
- 용법은 간단한데, Vue 3.3 전후에 따라 사용 방법이 달리지는 것만 유의하자.
const props = defineProps({
userId: {
type: Number,
required: true
}
})
useUser(toRef(props, 'userId')); // 3.3 버전 이전일 때
useUser(toRef(() => props.userId)); // 3.3 버전 이상일 때
🙄 잠깐! 사용처에서
toRef
방식으로props
를 컴포저블 인자로 전달하지 않고, 컴포저블에서 항상 반응형 변수임을 보장할 수는 없을까요?unref()
를 사용하면 가능하다!
unref()
는 말 그대로, 반응형 변수에서 값을 뽑아내는 함수이다.- 만약 반응형 변수가 아니면 그 값 자체를 리턴해준다.
const props = defineProps({
userId: {
type: Number,
default: 12,
}
})
const data1 = ref('안녕');
console.log(unref(props.userId)); // 12
console.log(unref(data1)); // 안녕
unref()
의 특성을 이용하여, 인자를 항상unref()
처리하고 이 값을computed
로 재선언하면 항상 반응형 변수임을 보장할 수 있다.
export function useUser(id) {
const userIdRef = compunted(() => unref(id));
watch(id, () => {
// 어떤 처리
});
}
3. 마치며…
- 이번 시간에는 컴포저블에 props를 인자로 넘길 때, 반응성을 유지하는 방법을 알아보았다.
- 첫 번째 방법은 props를 반환하는 getter 함수로 선언하는 것이고, 두 번째는 toRef를 사용하는 방법이다.
- 만약 컴포저블에서 인자가 반응형이 되도록 보장하고 싶다면,
unref
와computed
로 인자를 반응형 변수로 재선언하는 방법도 있다.
반응형
'개발 기술 > 개발 이야기' 카테고리의 다른 글
[JS] 메모리 누수는 왜 발생할까?(feat. 메모리 측정법) (10) | 2023.12.22 |
---|---|
구글 검색 엔진과 SEO을 알아보자!(with. SEO 측정 방법) (2) | 2023.11.12 |
[Vue] prop drilling을 예방하는 Provider Pattern 알아보기 (2) | 2023.09.30 |
팝오버를 라이브러리 없이 웹 API로 구현하는 법, Popover API (0) | 2023.09.17 |
DocumentFragment 객체로, 성능 좋게 DOM 조작하기 (0) | 2023.08.07 |
댓글