카테고리 없음

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 할당도 제대로 되질 않아서 일단 이 방법은 그만두었다. 혹시 더 좋은 방법을 아시는분은 가르쳐 주시면 감사합니다!