이슈
pc와 mo 버전에서 공통적인 부분은 함께쓰기 위해 composables에 ts를 따로 빼서 관리하는데, 빼는 과정에서 emit과 props가 잘 옮겨지지 않았다.
vue파일경로: src/views/fb-depth-select.vue
ts파일경로: src/composables/fb-depth-select.ts
ts 파일 따로 빼기 전 vue 소스 src/views/fb-depth-select.vue
<script setup lang="ts">
import { PropType, ref } from 'vue';
interface depthItem {
name: string;
value: string | number;
}
const emit = defineEmits(['update:selectCategories']);
const props = defineProps({
modelValue: {
type: Array as PropType<depthItem[]>,
default: () => [],
required: false,
},
})
//카테고리 세팅
const categoryList = ref<DepthItem[][]>([]);
categoryList.value = [...props.modelValue];
//선택한 값 (select컴포넌트 설정에 사용)
const selectedList = ref<DepthItem[]>([]);
selectedList.value = categoryList.value.map(v => v[0]);
// ...
</script>
부모 컴포넌트로 보낼 emit을 만들고 (emit 사용하는 부분은 생략) 부모에서 받을 props를 따로 선언하였다.
파일분리 시도 (실패케이스)
1. vue 소스 > src/views/fb-depth-select.vue
<script setup lang="ts">
import fbDepthSelectComposable from '@/composables/modules/fb-depth-select'
const {
categoryList,
selectedList,
//...
} = fbDepthSelectComposable();
</script>
composables/fb-depth-select.ts 로 소스를 옮기고
fb-depth-select.ts에서 fbDepthSelectComposable 라는 이름으로 내보낸 것을 import하였다.
return 하는 값들만 사용하기 위해 비구조화할당으로 선언하였다.
2. ts 소스 > src/composables/fb-depth-select.ts
import { PropType, ref, watch } from 'vue';
import { CustomEmit } from '@/interfaces/type';
interface DepthItem {
name: string;
value: string | number;
}
//여기가 이슈1
const emit = defineEmits(['update:selectCategories']);
//여기가 이슈2
const props = defineProps({
modelValue: {
type: Array as PropType<depthItem[]>,
default: () => [],
required: false,
},
})
export default function fbDepthSelectComposable(emit: CustomEmit<Emits>, props) {
//카테고리 세팅
const categoryList = ref<DepthItem[][]>([]);
categoryList.value = [...props.modelValue];
//선택한 값 (select컴포넌트 설정에 사용)
const selectedList = ref<DepthItem[]>([]);
selectedList.value = categoryList.value.map(v => v[0]);
return {
categoryList,
selectedList,
}
}
하단의 export default 로 fbDepthSelectComposable 라는 함수명으로 내보내고 그 위에 import, interface, emit, props 등을 위로 뺐다. 사실 emit과 props는 함수 안에 넣었었는데 에러가 나서 위로 뺐다. 그래도 defineProps와 defineEmits를 못찾는다고 오류가 났다.
해결방법
1. vue 소스 > src/views/fb-depth-select.vue
<script setup lang="ts">
import fbDepthSelectComposable, { emits as depthSelectEmits, props as depthSelectProps } from '@/composables/modules/fb-depth-select'
const emit = defineEmits(depthSelectEmits);
const props = defineProps(depthSelectProps);
const {
categoryList,
selectedList,
disabled,
selectCategory
} = fbDepthSelectComposable(emit, props);
</script>
포인트 1
defineEmits와 defineProps는 여기 안에서만 사용이 가능하다. (composables/ts 파일 안에서는 찾을 수 없음.)
포인트 2
composables 안에 있는 emits를 depthSelectEmits로, props를 depthSelectProps로 사용하기로 한다.
(emits as depthSelectEmits, props as depthSelectProps)
포인트 3
원래 소스처럼
const emit = defineEmits(['update:select-category']) 대신에
const emit = defineEmits(depthSelectEmits) 로 바꿔준다.
* composables파일에서 보내주는 depthSelectEmits 에는 ['update:select-category'] 이게 들어있음.
(아래 composables 파일 참고)
포인트 4
props도 emit과 동일한 원리로 해준다.
포인트 5
defineEmits와 defineProps로 진짜 우리가 생각하는 emit과 props 가 되었으므로 이걸 composables 파일 함수인 fbDepthSelectComposable에 넘겨준다.
fbDepthSelectComposable(emit, props)
2. composables/ ts 소스> src/composables/fb-depth-select.ts
import { PropType, ref, watch } from 'vue';
import { CustomEmit } from '@/interfaces/type';
interface DepthItem {
name: string;
value: string | number;
}
type Emits = 'update:selectCategory';
const emits: Emits[] = ['update:selectCategory'];
const props = {
modelValue: {
type: Array as PropType<DepthItem[][]>,
default: () => [],
required: false,
},
}
export default function fbDepthSelectComposable(emit: CustomEmit<Emits>, props) {
//카테고리 세팅
const categoryList = ref<DepthItem[][]>([]);
categoryList.value = [...props.modelValue];
//선택한 값 (select컴포넌트 설정에 사용)
const selectedList = ref<DepthItem[]>([]);
selectedList.value = categoryList.value.map(v => v[0]);
return {
categoryList,
selectedList,
}
}
export {
emits,
props,
}
포인트 1
vue파일 포인트 2번에서 as로 선언한 emits과 props는 맨 하단의 export로 내보낸 이 emits, props이다.
** emits과 props는 function 위에 const로 선언되어있다.
포인트 2
vue파일 포인트5번에서 보내준 emit과 props를 여기서 받는다.
export default function fbDepthSelectComposable(emit, props) {}
포인트 3
emit과 props는 vue파일에서 쓰던 것과 동일하므로 (define된 애들임) 그대로 사용하면 된다.
정리
composables 안에서는 defineProps나 defineEmits를 쓰지 못하므로 vue파일에서 선언해서 composables 함수로 넘겨준다.
반응형
'Vue > Vue3' 카테고리의 다른 글
[Vue3] 배열 Array Watch 제대로 하는법 (lodash의 _cloneDeep) (0) | 2022.01.24 |
---|---|
[vue3] 부모컴포넌트에서 자식컴포넌트로 보낸 데이터 값 변경 감지하기 (props 변경 감지하기) (0) | 2022.01.12 |
[Vue3] vue에서 전체선택 체크박스 로직 구현하기 (checkbox select all) (0) | 2022.01.03 |
[Vue3] 컴포넌트간 통신하기 vue2의 eventbus, Vue3에서는 mitt (emitter) (0) | 2021.12.15 |
[Vue2 vs Vue3] vue에 있는 ref 접근하기 ! this.$ref 사용하기 (template refs) (0) | 2021.12.07 |