computed

computed 계산 속성

computed 속성은 데이터를 실시간으로 계산하려 할 때 사용한다. 데이터를 실시간으로 계산한다는 것은 어떤 의미인지 왜 필요한지 예제를 통해 살펴본다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue computed 속성의 필요성</title>
</head>
<body>
    <div id="app">
        <div>
            <label>
                Nickname
                <input type="text" v-model="nickname" v-on:input="nickname = $event.target.value">
            </label>
        </div>
        <h5>닉네임 글자 수 : {{nickname.length}}</h5>
        <h5>사용 가능 여부 : {{nickname.length >= 2 && nickname.length <= 6}}</h5>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    nickname:""
                };
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

예제는 2글자 이상 6글자 이하의 닉네임을 입력하면 true, 아니면 false를 출력하도록 구성되어 있다. 결론적으로 실행은 되지만 대부분의 에디터에서 구문 오류 표시가 발생한다. HTML에서 사용하기 부적합한 문자인 <, > 때문이다. 그 외의 문제점까지 정리하면 다음과 같다.

  • HTML 구문 오류로 인식

  • 가독성 저하

  • 중복 코드 발생

computed 속성을 사용하면 다음과 같이 코드가 변경된다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue computed 속성의 필요성</title>
</head>
<body>
    <div id="app">
        <div>
            <label>
                Nickname
                <input type="text" v-model="nickname" v-on:input="nickname = $event.target.value">
            </label>
        </div>
        <h5>닉네임 글자 수 : {{nicknameLength}}</h5>
        <h5>사용 가능 여부 : {{nicknameAvailable}}</h5>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    nickname:""
                };
            },
            computed:{
                nicknameLength(){
                    return this.nickname.length;
                },
                nicknameAvailable(){
                    return this.nickname.length >= 2 && this.nickname.length <= 6;
                }
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

실행 결과는 동일하지만 기존 예제의 문제점이 해결되었다.

사용법

computed 속성은 다음과 같이 작성한다.

const app = Vue.createApp({
    //data(){ return {}; },
    computed:{
        이름(){
            return 값;
        },
    }
});

computed 영역 내부에 값을 반환하는 함수를 만들어야 하며, 함수의 이름이 변수처럼 사용된다. 함수 내에서는 this 키워드를 이용하여 Vue instance 내부 요소들을 사용할 수 있다.

데모 - 아이디 형식 검사

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue computed demo</title>
</head>
<body>
    <div id="app">
        <div>
            <label>
                ID
                <input type="text" v-model="id">
            </label>
        </div>
        <h6 v-text="result"></h6>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    id:""
                };
            },
            computed:{
                result(){
                    const regex = /^[a-z][a-z0-9_]{7,19}$/;
                    if(regex.test(this.id)){
                        return "사용 가능한 아이디 형식입니다";
                    }
                    else {
                        return "아이디는 영문 소문자로 시작하는 8~20자 이내의 영문 소문자, 숫자, _로 작성해주세요";
                    }
                },
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

데모 - 이메일 작성

이메일은 @를 기준으로 접두사(emailPrefix)와 접미사(emailSuffix)로 나눠지도록 구성하였다. 이 경우 실제 데이터는 emailPrefixemailSuffix이며, 전체 이메일은 computed 속성으로 만들어서 설정 및 확인할 수 있도록 구성한다. computed는 기본적으로 get만 가능하기 때문에 이 경우 computed를 get, set이 가능한 객체 형태로 정의할 수 있다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue computed getter/setter</title>
</head>
<body>
    <div id="app">
        <div>
            Email : 
            <input type="text" v-model="email">
        </div>
        <h5>설정된 이메일 : {{email}}</h5>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    emailPrefix:"",
                    emailSuffix:""
                };
            },
            computed:{
                email:{
                    get(){
                        if(this.emailPrefix && this.emailSuffix){
                            return this.emailPrefix + "@" + this.emailSuffix;
                        }
                        else{
                            return "";
                        }
                    },
                    set(email){
                        const idx = email.indexOf("@");
                        if(idx < 0) {
                            return;
                        }

                        this.emailPrefix = email.substring(0, idx);
                        this.emailSuffix = email.substring(idx + 1);
                    }
                },
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

주의사항

computed 사용 시 주의사항은 다음과 같다.

  • Vue instance 내부의 다른 항목에 접근할 경우 반드시 this 키워드를 사용해야한다.

  • 너무 많은 연산을 수행하지 않도록 구성한다.

  • 가급적 Vue data에 대한 계산을 수행하도록 구성한다.

Last updated