[ Reference ]
https://vuejs.org/guide/essentials/template-refs.html
Template Refs | Vue.js
vuejs.org
Vue 의 선언적 렌더링은 대부분 직접적인 DOM 작업을 추상적으로 실행하지만(* 간접적으로 실행한다는 의미) 일을 하다 보면 실제 DOM element에 직접 접근해야할 때가 있다. 이런 경우에는 ** ref ** 의 특별한 속성을 사용해서 해결할 수 있다. ** ref ** 는 ** v-for ** 의 ** key ** 속성과 비슷한 특수 속성이다. 특정 DOM element, 혹은 하위 구성 element 인스턴스를 마운트된 이후에 이를 직접 참조할 수 있도록 도와준다. 타사 라이브러리를 초기화할 때도 이런 방법은 유용할 수 있다.
1. Accessing the Refs
Composition API 에서 레퍼런스를 얻기 위해서는 먼저 ** ref ** 를 동일한 이름으로 선언해야 한다.
<script setup>
import { ref, onMounted } from 'vue'
// declare a ref to hold the element reference
// the name must match template ref value
const input = ref(null)
onMounted(() => {
input.value.focus()
})
</script>
<template>
<input ref="input" />
</template>
주의해야 할 점은 컴포넌트가 마운트된 이후에 접근이 가능하다는 점이다. template 표현식에서 곧바로 input에 접근하고자 한다면 null 값으로 나올 것이다. 왜냐하면 첫 번째 렌더 이후까지는 그 element 가 아직 존재하지 않기 때문이다.
2. Refs inside v-for
만약 ** ref ** 가 ** v-for ** 안에서 사용되는 경우, 해당하는 ** ref ** 는 반드시 마운트 이후에도 element 가 있는 배열을 포함해야 한다.
<script setup>
import { ref, onMounted } from 'vue'
const list = ref([1, 2, 3])
const itemRefs = ref([])
onMounted(() => {
alert(itemRefs.value.map(i => i.textContent))
})
</script>
<template>
<ul>
<li v-for="item in list" ref="itemRefs">
{{ item }}
</li>
</ul>
</template>
(* 위의 예제는 Try it in Playground 링크에서 기재된 내용이며, 저 코드에서 alert 창으로 나오는 값은 "1, 2, 3" 이다) 한 가지 주의해야할 점은 ** ref ** 에 들어간 배열이 원본 배열과 동일한 순서를 보장하지 않다는 점이다.
3. Function Refs
문자열 대신에 ** ref ** 속성을 이용해서 함수를 바인딩할 수 있다. ** ref ** 로 바인딩한 함수는 컴포넌트를 업데이트할 때 호출한다. 그리고 호출된 후에 element 에 대한 참조를 어디에 저장할 건지에 대해서 매우 유연한 방식을 제공해줄 것이다. 이 함수는 첫 번째 인자로 element 에 대한 참조를 받는다. (* 여기서 참조는 refernece 라는 용어를 사용했는데, 쉽게 한글로 생각해 본다면 그 element 를 DOM Tree 에서 참조한다 라는 의미로 받아들이면 될 것 같다)
<input :ref="(el) => { /* assign el to a property or ref */ }">
한 가지 더 생각해볼 수 있는 건 ** :ref ** 로 동적으로 바인딩을 하고 ** :ref ** 에 대한 string 으로 된 이름 대신에 함수를 전달할 수 있게 된다. 만약, element 가 unmounted 되면 인자는 null 값을 받을 것이다. 물론, 바인딩 할 수 ㅣㅇㅆ는 건 인라인 함수가 아니라 메소드가 될 수도 있다.
4. Ref on Component
** ref ** 는 자식 컴포넌트에도 적용할 수 있다.
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
const child = ref(null)
onMounted(() => {
// child.value will hold an instance of <Child />
})
</script>
<template>
<Child ref="child" />
</template>
이렇게 된 경우 부모 컴포넌트가 자식 컴포넌트의 모든 속성과 메소드에 대해서 완전히 접근할 수 있게 된다. 그렇게 되면 부모와 자식 간에 긴밀하게 연결돼야 하는 세부적인 사항들을 쉽게 만들 수 있게 되지만 최대한 자제하는 것이 좋다. 또, 이런 부모와 자식 간의 소통은 ** props ** 나 ** emits ** 로 구현할 수 있기 때문에 먼저 이런 인터페이스들을 사용해보고, 그 다음에 ** ref ** 를 사용하는 방법을 생각해봐야 한다.
<script setup> 을 사용하는 경우, 기본적으로 private, 비공개다. 이 script 문을 사용하는 하위 컴포넌트를 참조하는 부모 컴포넌트는 ** defineExpose ** 매크로를 사용해서 public 인터페이스를 노출하도록 선택하게 해야 접근 권한이 생기게 된다. (* 읽으면서 느꼈지만 그냥 쓰지 말라고 하는 거 같다... 번역하지 말 걸)
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
위에서 처럼 자식 컴포넌트가 작성되었다고 하면 부모 컴포넌트는 ** ref ** 를 이용해서 {a: number, b: number} (* 여기서 number 는 타입) 모양의 인스턴스를 가져오게 될 것이다.
'(준)공식 문서 > Vue.js' 카테고리의 다른 글
[ Vue.js 3 공식 문서 ] 2. Essentials - Components Basics (Component, Props, Emits ) (0) | 2022.02.28 |
---|---|
[ Vue.js 3 공식 문서 ] 2. Essentials - Watchers (0) | 2022.02.22 |
[ Vue.js 3 공식 문서 ] 2. Essentials - Lifecycle Hooks (0) | 2022.02.22 |
[ Vue.js 3 공식 문서 ] 2. Essentials - Form Input Binding (v-model) (0) | 2022.02.22 |
[ Vue.js 3 공식 문서 ] 2. Essentials - Event Handling (v-on) (0) | 2022.02.22 |