[Vue3] 객체 기본값 설정시 factory 함수 사용 (feat. undefined)
Vue를 쓰다 보면, props나 data에서 기본값(default)을 설정해야 할 때가 자주 있다. 객체나 배열처럼 참조형 데이터의 기본값을 설정할 때는 반드시 factory 함수를 써야 한다. 왜 factory 함수를 꼭 써야 하는지, 어떤 문제가 발생할 수 있는지 다루어보려한다.
1. 기본값을 직접 할당하면 발생하는 문제
props: {
options: {
type: Object,
default: {}
}
}
default: {}는 프로그램이 시작될 때 단 한 번만 평가되어, 하나의 {} 객체가 메모리에 만들어지게 된다.
이후 컴포넌트를 여러 번 만들어도, Vue는 이 {} 객체를 계속 재사용하게 된다.
2. 실제로 생기는 문제
<my-component />
<my-component />
예를 들어, <my-component />를 두 번 썼다고 생각해 보자.
즉, 첫 번째 컴포넌트에서 options.someValue = 123처럼 데이터를 바꾸면, 두 번째 컴포넌트의 options도 함께 바뀌어버리게 된다.
3. 왜 그럴까?
const a = {};
이 {}는 코드가 로드될 때 한 번만 만들어지고, a가 계속 그 객체를 참조하게 된다.
Vue의 default: {}도 똑같이, 처음 만들어진 객체를 계속 재사용하기 때문에 이런 문제가 생기게 되는 것이다.
4. factory function으로 해결하기
이 문제를 해결하려면 아래처럼 factory 함수로 작성해야 한다.
props: {
options: {
type: Object,
default: () => ({})
}
}
컴포넌트 인스턴스가 새로 만들어질 때마다 () => ({}) 함수가 호출돼서 새로운 {} 객체가 반환된다.
각 인스턴스가 서로 다른 객체를 가지게 되므로, 데이터가 서로 엉키거나 공유되지 않는다.
5. undefined도 factory function을 써야 할까?
원래는 객체나 배열만 factory함수로 감싸야한다. 기본적으로 undefined는 primitive 타입이라서, 직접 default: undefined라고 써도 문제가 없다. 하지만, Vue의 내부 동작에서 default에 Object, Array가 지정된 타입과 default 값의 타입을 일관적으로 처리하려고 할 때, factory function 형태가 요구될 수 있다. default: () => undefined처럼 factory function 형태로 작성해도 전혀 문제 없으며, 오히려 이렇게 작성하지 않는 경우 에러가 발생하기도 한다. 따라서 타입 일관성이나 Vue의 내부 처리와 호환성을 높이기 위해 이와 같이 작성하는 것도 좋다.
[참고문서 : https://vuejs.org/guide/components/props.html#prop-validation ]