본문 바로가기
front/vue

[vue3 공식문서 번역]Essentials.12.Template Refs

by juniKang 2022. 4. 27.

Template Refs

뷰의 선언적인 렌더링 모델이 대부분의 직접적으로 DOM을 다루는 작업을 추상화했지만, 여전히 근본적인 돔 엘리먼트에 직접적으로 접근해야 하는 경우가 있다. 그래서, 특별한 ref 어트리뷰트를 사용할 수 있다.

<input ref="input">

ref는 v-for챕터에서 다뤘던 key 어트리뷰트와 비슷한 특별한 어트리뷰트다. 특정한 톰 엘리먼트나 또는, 마운트한 자식 컴포넌트 인스턴스로 부터 직접적인 참조를 얻도록 해준다. 이건 필요할 때 매우 유용한데, 예를 들면, 프로그래밍적으로 마운트된 컴포넌트의 input에 포커스를 맞추거나, 엘리먼트에 써드 파티 라이브러리를 초기화 할 때 등이다.

 

Refs에 접근하기

Composition API에서 참조를 얻기 위해, 같은 이름으로 ref를 선언해야 한다:

<script setup>
import { ref, onMounted } from 'vue'

// 엘리먼트 참조를 갖기 위해 ref를 선언해야 함
// template ref 값과 이름이 일치해야함
const input = ref(null)

onMounted(() => {
  input.value.focus()
})
</script>

<template>
  <input ref="input" />
</template>

<script setup>을 안쓰면, setup()의 ref도 같이 리턴해야만 한다:

export default {
  setup() {
    const input = ref(null)
    // ...
    return {
      input
    }
  }
}

컴포넌트가 마운트된 이후에만 ref에 접근할 수 있음을 기억해라. 템플릿 표현식에서 input에 접근하길 시도하면, 첫 렌더링 에서는 null 일거다. 그건 엘리먼트가 첫 렌더가 끝나기 전까지 존재하지 않기 때문이다. 

 

만약 template ref의 변화를 보고 싶다면, ref가 null 값을 가진 경우를 세어봐라.

watchEffect(() => {
  if (input.value) {
    input.value.focus()
  } else {
    // 아직 마운트되지 않거나, 엘리먼트가 언마운트 됨 (예; v-if)
  }
})

 

v-for 안에있는 Refs

// 3.2.25나 그 이상 버전이 필요함

ref가 v-for안에서 사용될 때는, 대응하는 ref가 마운트 이후에 엘리먼트들이 채워지는 배열값을 담고 있을 수 있다:

<script setup> 
import { ref, onMounted } from 'vue'

const list = ref([
  /* .... */
])

const itemRefs = ref([])

onMounted(() => console.log(itemRefs.value))
</script>

<template>
  <ul>
    <li v-for="item in list" ref="itemRefs">
      {{ item }}
    </li>
  </ul>
</template>

알아둬야 할건, ref 배열은 소스 배열의 같은 순서를 보장하지 않는다.

 

Function Refs

string key 대신에, ref 어트리뷰트는 함수에 바인딩될 수 있다. 이 ref 어트리뷰트는 각각의 컴포넌트가 업데이트 되었을 때 호출되며, 엘리먼트 참조를 저장할 위치에 대한 유연함을 준다. 함수는 첫번째 아규먼트를 엘리먼트 참조로 받는다.:

<input :ref="(el) => {/* el을 프로퍼티나 ref에 배정한다 */ }">

동적인 :ref 바인딩을 사용해서 ref 이름 문자열 대신에 함수를 넘길 수 있다. 엘리먼트가 언마운트 되면 아규먼트는 null이다. 물론, 인라인 함수대신에 메소드를 쓸 수도 있다. 

 

컴포넌트에서 Ref

ref는 child 컴포넌트에서도 사용될 수 있다. 이 경우에 참조는 컴포넌트 인스턴스의 참조가 된다:

<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'

const child = ref(null)

onMounted(() => {
  // child.value는 <Child />의 인스턴스를 홀딩함
})
</script>

<template>
  <Child ref="child" />
</template>

만약 child component가 <script setup>을 안쓰고 Options API를 쓰면, 참조되는 인스턴스는 차일드 컴포넌트의 this와동일할 것이다. 이 this는 부모 컴포넌트가 자식 컴포넌트의 모든 프로퍼티와 메소드에 접근할 수 있다는 것을 가르킨다.  이건 부모 자신간에 강력한 결합을 만들기 쉽다. 그래서 컴포넌트 refs는 틀림없이 필요한 경우에만 사용해야 한다. - 대부분의 경우에서 부모/ 자식의 상호작용은 기본적인 props와 emit인터페이스로 먼저 구현을 시도할 수 있다. 

 

예외적으로, <script setup>을 사용하는 컴포넌트는 기본적으로 private 이다: <script setup>을 사용하는 자식 컴포넌트를 참조하는 부모 컴포넌트는 자식 컴포넌트가 defineExpose 매크로를 사용해서 public 인터페이스를 선택적으로 노출하기 전에는 아무것도 접근할 수 없다.

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

부모가 template refs를 통해서 컴포넌트의 인스턴스를 얻었을 때, 찾은 인스턴스는 { a: number, b: number }형태일 것이다.(refs는 자동적으로 노말 인스턴스처럼 언래핑된다.)

 

댓글