B.TIL 06 : vue $ref 활용하기

Props & Event

컴포넌트는 Vue.js의 꽃이다. 재사용 가능한 코드를 캡슐화(컴포넌트화)해서 재사용을 할 수 있고, 컴포넌트간에 통신을 활용해 복합적인 기능 구현을 완성을 할 수 있게 된다.

Props & Event는 단방향 데이터 흐름(바인딩)을 보여주는 대표적인 기능들이다.
그림을 보듯 우리는 Props를 통해 부모 컴포넌트에서 자식 컴포넌트로 '데이터'를 보낼 수 있고
Event와 Emit을 통해 부모에게 받은 데이터를 가공해 다시 부모 컴포넌트에 송신할 수 있다.

기본적으로 리액트와 뷰 모두 데이터의 플로우는 '단방향'= '부모->자식'으로만 한정 짓고있다.
이와 같이 구성한 이유는 하위 컴포넌트에서 상위 컴포넌트를 조작할 경우 앱의 데이터 플로우의 추론이 어렵고, 작은 컴포넌트가 전체적인 웹 페이지를 망가뜨리는 경우가 발생하기 때문이다.

Refs

DOM과 엘리먼트를 직접 조작하는 메서드들은 예전부터 많이 쓰였고, 지금도 많이 사용하고 있다.

getElementsById getElementsByClassName Document.creatElement()
등등 고전적인 메서드를 활용해 DOM을 직접 조작해 HTML 구조를 자바스크립트로 변경이 가능하다.

하지만 Vue에서는 이런 메서드의 사용을 피하라고 권고하고 있다.
웹 브라우저 단에서는 DOM에 변화가 일어나면 웹 브라우저가 CSS를 다시 연산/레이아웃/구성하며 페이지 리페인트를 하기 때문에 시간 로스가 심해지기 때문이다.

물론 기본적으로 리액트와 뷰 모두 실제 DOM이 아닌 Virtual DOM을 사용하기 때문에
DOM조작메서드를 쓴다고 해도 DOM처리 횟수가 생각보다 많아 지지는 않지만(버츄얼돔을 쓰게되면 실제 DOM에 렌더링하는 시점에 '변경부분만 리렌더링함') 어쨌건 이러한 메서드의 사용은 지양하는게 최근 프론트엔드의 개발자의 트렌드라고 보면 된다.

서설이 좀 길었다. 그래서 ref가 뭐냐면..?

refs는 뷰에서 지원하는 강력한 기능이다.
공식문서에 기재되다 싶이 ref는 예외적인 상황에 쓰이는 강력한 기능인데,
사용처는...

첫째. JavaScript로 Props&Event 거치지않고 자식컴포넌트 직접 접근
둘째. DOM조작 메서드 없이 엘리먼트 조작

크게 이 두 가지가 있겠다.

사용방법도 매우 쉬운데 class명을 명명하는 것 처럼 HTML 엘리먼트에 ref="test" 라고 명명 지어주면 된다.

예제코드를 보자.

<template>
    <div class="info">
        <div class="input-box">
            <input class="name" ref="name" type="text" placeholder="이름" v-model="info.name"/>
            <input class="age" ref="age" type="text" placeholder="나이" v-model="info.age"/>
            <input class="job" ref="job" type="text" placeholder="직업" v-model="info.job" /> 
            <button class="check" type="button" @click="[doCheck(), sendInfo()]">확인</button> 
        </div>
    </div>
</template>

<script>
import store from '../store/index.js'
export default {
    data() {
        return {
            info: {
                name: '',
                age: '',
                job: ''
            }
        }
    },
    methods:{
        doCheck(){
            if (!this.info.name){
                this.$refs.name.focus();
            }else if (!this.info.age){
                this.$refs.age.focus();
            }else if (!this.info.job){
                this.$refs.job.focus();
            }else if (this.info.name && this.info.age && this.info.job){
                alert('모두 입력되었습니다!');
            }
        },
        sendInfo(){
            if (this.info.name && this.info.age && this.info.job){
                store.commit('setInfo', this.info)
            }
        }
    }
}
</script>

<style lang='scss'>
    .info {

        .input-box {
            display : flex;
            vertical-align : middle;
            flex-direction : column;
            margin-top: 35px;

            .name {
                width : 20%;
                margin : 6px;
                padding : 4px;
            }

            .age {
                width : 20%;
                margin : 6px;
                padding : 4px;
            }

            .job {
                width : 20%;
                margin : 6px;
                padding : 4px;
            }

            .check {
                width : 20%;
                margin : 6px;
                padding : 4px;
                color : white;
                background-color : #ff204b;
            }
        }
    }
</style>

input tagref를 걸었고, javascript method를 통해 엘리먼트에 직접 접근해 포커스를 명령한다. 이를 통해 데이터가 채워지지않은 인풋 태그라인에 포커스를 통해 보여주게끔 한다.
모든 데이터가 채워지면 포커스 되지않고 성공 alert가 발생한다.

좋은 웹페이지 즐겨찾기