[vue] ref 속성 (feat. 주의할 점)

1. ref란?

1) 정의

ref란 뷰에서 컴포넌트 또는 DOM에 접근하기 위해 사용하는 속성입니다.

마운트된 요소에만 적용가능합니다. 마운트 되지 않은 요소에 사용하면 ref undefined가 발생합니다.

2) 사용법

  • 접근 대상 ref 속성 명시
  • 사용 대상 this.refs 로 접근

제일 많이 실수 하는 부분중 하나는 ref와 refs의 스펠링을 구분하지 못하는 것입니다.

// App.vue
<template>
  <div>
    안녕하세요
    <vue-person
      ref="VuePerson"
      name="dorosy"
    />
  </div>
</template>

<script>
import VuePerson from '@comp/VuePerson'

export default {
  name: 'App',
  components: {
    VuePerson,
  },
  mounted() {
    const name = this.$refs.VuePerson.name
    console.log('name', name) // name dorosy
  }
}
</script>
// VuePerson.vue
<template>
  <div>
    Hi
  </div>
</template>

<script>
    export default {
        name: 'VuePerson',
        props: {
            name: {
                type: String,
                default: ''
            }
        },
        methods: {
            sayHi () {
                console.log(`Hi My name is ${this.name}`)
            }
        }
    }
</script>

3) 특징

대상 속성에 모두 접근가능하기 때문에 함수 호출도 가능합니다.

다만, 이렇게 되면 너무 jquery느낌이 납니다. 필요한 경우에만 사용합시다.

// App.vue
<template>
  <div>
    안녕하세요
    <vue-person
      ref="VuePerson"
      name="dorosy"
    />
  </div>
</template>

<script>
import VuePerson from '@comp/VuePerson'

export default {
  name: 'App',
  components: {
    VuePerson,
  },
  mounted() {
    // 대상의 sayHi 메서드 호출
    this.$refs.VuePerson.sayHi() // Hi My name is dorosy
  }
}
</script>
// VuePerson.vue
<template>
  <div>
    Hi
  </div>
</template>

<script>
    export default {
        name: 'VuePerson',
        props: {
            name: {
                type: String,
                default: ''
            }
        },
        methods: {
            sayHi () {
                console.log(`Hi My name is ${this.name}`)
            }
        }
    }
</script>

2. 주의할 점

1) 마운트 되지 않은 요소에 사용

v-if=false 로 렌러링 되지 않았거나, created()에서 사용하면 ref undefined 또는 속성이 없다는 에러를 만나게 됩니다.

2) ref, refs 스펠링 틀리는 경우 생각보다 많이 있습니다.

  • 대상 - ref
  • 접근할 때 - refs

3) computed 에서 사용하는 경우

이 경우도 생각보다 많은데

뭔가 렌더링 여부를 검사하고 싶은데 방법이 없나, 아 computed를 사용하면 되겠다 이런 생각으로 도달한 경우 (제가 그랬습니다. 아니면 말구)

computed에서 제대로 확인할 수 없습니다.

<template>
  <div>
    안녕하세요
    <vue-person
      ref="VuePerson"
      name="dorosy"
    />
  </div>
</template>

<script>
import VuePerson from '@comp/VuePerson'

export default {
  name: 'App',
  components: {
    VuePerson,
  },
  computed: {
    isExist() {
      console.log('isExist', this.$refs)
      return this.$refs.VuePerson ? true : false
    }
  },
  created() {
    console.log('created', this.isExist)
  },
  mounted() {
    console.log('mounted', this.isExist)
  }

}
</script>

4) watch

computed와 비슷한 맥락, 뭔가 렌더링 되는 그 순간을 어떻게든 잡아보겠다라는 집념으로 watch 를 사용합니다. (저의 이야기입니다.)

watch에 걸리는 일은 없습니다.

<template>
  <div>
    안녕하세요
    <vue-person
      ref="VuePerson"
      name="dorosy"
    />
  </div>
</template>

<script>
import VuePerson from '@comp/VuePerson'

export default {
  name: 'App',
  components: {
    VuePerson
  },
  data() {
    return {
      isExist: this.$refs.VuePerson
    }
  },
  watch: {
    isExist(val) {
      console.log('isExist', val)
    },
    'refs.VuePerson' (val) {
      console.log('refs.VuePerson', val)
    }
  }
}
</script>

이쯤되면 이런 생각도 들었습니다. 왜 ref는 될때가 있고, 안될때가 있지... 물로 제가 공식 문서 제대로 안봐서 생긴 잘못입니다.

5) 상태 추적 어려움

jquery 처럼 직접 접근하는 방식이기 때문에 상태 추적하기가 생각보다 어려워집니다.

이유는 모르겠지만 vue 개발하다보면, 안쪼개고, 하나의 파일에다 전체 로직 넣어 놓는 경우가 많은데 그 중에 ref 몇개만 섞여 있어도 데이터가 어떻게 변하는지 추적하기 어려워집니다.
(리팩토링 하는데 너무 힘들었던 경험이 있습니다.)

진짜 이거 아니면 안되겠다.그럴 때 사용합시다.
(생각보다 그런 경우 별로 없어, 그냥 그 상황에서 쉽게 하려고 쓰는듯)

좋은 웹페이지 즐겨찾기