카테고리 없음
Vue3에서 동적 ref를 자식 Component의 input에 할당하고 싶을 때
곽빵
2023. 9. 2. 14:01
개요
문제가 복수의 input Element가 있고 특정 동작에 의해 그 복수의 input Element에서 조건에 해당되는 하나의 input Element에 포커스가 할당되게끔 하고 싶다. 지금의 구조는 그 Input Element는 자식 Component인 Input이라는 컴포넌트로 구성되어 있다.
부수적인 조건으로
- 부모에서 해당 Ref를 컨트롤 할 수 있어야 한다.
- 타입스크립트로 작성
- 자식 컴포넌트에 부모에 종속될 듯한 로직을 추가하지 말자.
부모 컴포넌트
<script lang="ts" setup>
import Input from '@/components/Atoms/Form/Input.vue';
const questionInputRefs = ref<HTMLInputElement[]>([]);
const setQuestionInputRef = (index: number) => (el: HTMLInputElement) => {
if (el) {
questionInputRefs.value[index] = el
}
};
const onClearQuestion = (index: number) => {
questionInputRefs.value[index].focus();
};
</script>
<template>
<section v-for="(question, i) of request.questions" :key="i" ttle="질문">
<Input v-model:value="question.content" :setRef="setQuestionInputRef(i)" />
<button @click="onClearQuestion(i)">
클리어
</Button>
</section>
</template>
자식 컴포넌트
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
const props = defineProps<{
setRef?: (el: HTMLInputElement) => void;
}>();
const inputRef = ref<HTMLInputElement>();
onMounted(() => {
if (props.setRef && inputRef.value) {
props.setRef(inputRef.value);
}
});
</script>
<template>
<input :class="$style.input" ref="inputRef" />
</template>
- questionInputRefs 라는 복수의 ref를 담을 상태를 만든다.
- setQuestionInputRef는 고차함수로써 부모에서 index를 설정하고 자식에서 Element를 설정하게끔 두단계로 이루어진 함수로 구성한다.
- 자식에서 setQuestionInputRef를 받으면 기존에 존재하던 Ref를 setQuestionInputRef에 설정한다.
- 이제 클리어 버튼을 눌러 onClearQuestion를 실행시키면 해당되는 인덱스의 ref에 접근해 focus()를 함으로써 문제없이 포커스가 된다.
setQuestionInputRef의 구조가 읽기 어려워서 더 좋은 방법을 모색하고 있지만 지금까지는 딱히 떠오르는 방법은 없다. ChatGPT에서는 자식 컴포넌트 자체에 Ref를 부여해 그 ref로 자식 컴포넌트가 가지고 있는 함수를 실행시킬수 있다고는 하지만 애초에 컴포넌트 자체에 Ref 할당도 제대로 되질 않아서 일단 이 방법은 그만두었다. 혹시 더 좋은 방법을 아시는분은 가르쳐 주시면 감사합니다!