본문 바로가기

Vue JS

Vue.js 시작하기 04 - computed와 watch ( vs methods)

- HTML > body -

 

<!-- < computed 속성 vs methods 속성 > -->
    <div id="app-1">
        <div>
            <p> original msg : {{ msg }} </p>
        </div>
        <div>
            <p> app1.msg = "changed msg"; </p>
        </div>
        <div>
            <p> reversed msg from computed : {{ reversedByComputed }}</p> <!--computed로부터 값을 부를 때는 함수 실행()을 하지 않고 data 속성 변수처럼 부릅니다.-->
        </div>
        <div>
            <p> reversed msg from methods : {{ reversedByMethods() }} </p> <!-- 실행시킬 때는 함수명() 소괄호 붙여주기 -->
        </div>
    </div>
    <div>----------------------------------------------------<br></div> 


    <!-- < computed 속성 vs watch 속성 > -->
    <div id="app-2">
        <p> {{ fullName }} </p>
        <p> input below line in console and watch logs</p>
        <p> app2.firstName = 'Tom'; </p>
        <p> app2.lastName = 'Cruise'; </p>
    </div>
    <div>----------------------------------------------------<br></div> 

    <!-- < watch 속성 활용 > -->
    <div id="app-3">
    <p>
        yes/no 질문을 물어보세요:
        <input v-model="question">
    </p>
    <p>{{ answer }}</p>
    </div>
    <div>----------------------------------------------------<br></div>

 

- script -

// < computed 속성 vs methods 속성 >
        //앞에서 콧수염 방식 안에 간단한 JavaScript 표현식을 넣을 수 있다고 했습니다. 
        //예) {{ numVal * 2 }} / {{ boolVal ? boolVal : false }}
        //근데 표현식이긴 한데 너무 길어지면 가독성도 떨어지고 표현이 복잡해집니다.
        //예) {{ msg.split('').reverse().join('') }} 
        //예시기는 하지만 벌써 함수가 세 개나 들어갔는데, 이게 과연 이렇게 쓰는 게 맞는 것일까?
        //직관적이지 않고, 여러 곳에서 불러야 한다면 유지보수도 어려워집니다.
        //이럴 때 쓰면 좋은 기술이 바로 computed 속성입니다. 
        //복잡할수록 콧수염 방식 안에 표현식으로 쓰지 말고 computed를 써야 합니다.
        //methods에 함수를 정의한 뒤 불러다 쓰는 방식으로도 똑같은 기능을 구현할 수 있지만 차이점이 있습니다.
        //reversedByComputed (computed에서 불러다 씀)는 계산한 결과 값을 들고 있다가 호출되면 그 값을 넘겨줍니다.
        //reversedByComputed는 여러 번 불러도 가지고 있던 값을 그대로 돌려주기 때문에 함수를 실행하는 횟수는 한 번뿐입니다.
        //reversedByComputed는 의존하고 있는 값, msg가 바뀔 때만 함수를 새로 실행해서 결과 값을 새로 들고 있습니다.
        //reversedByMethods (methods에서 불러다 씀)는 10번 부르면 10번 다 일일이 함수를 실행해 보고 그 결과를 되돌려줍니다.
        //reversedByMethods 를 쓰면 꼭 필요하지 않은 경우에도 getter함수를 여러 번 부르게 됩니다. 
        //로직이 복잡해질수록 computed에서 불러다 쓰는지, 아니면 methods에서 불러다 쓰는지에 따라 큰 차이를 만들게 됩니다.
        //물론 굳이 캐싱을 가져다 쓰지 않지 않기를 원한다면 일부러 methods를 불러다 쓰는 게 더 좋습니다.
        //캐싱을 가져다 쓰지 않을 만한 경우는 예를 들어서  같은 경우입니다. 
        //computed를 사용한다면 Date.now()는 다른 값을 참조하고 있지 않기 때문에 내부적으로 그 값이 바뀌더라도 함수를 새로 실행하지 않고 처음에 실행했던 결과 값을 그대로 들고 있다가 되돌려주게 됩니다.
        //시간을 엄청 민감하게 다루어야 하는 경우에는 부를 때마다 새로 실행하도록 methods에서 부르면 좋습니다.
        //단, 의존하고 있는 값, data 속성, 여기서는 msg 가 바뀔 때마다 결과값도 같이 갱신해주는 기능은 computed 에서 부르든 methods 에서 부르든 똑같습니다.

        var app1 = new Vue({
            el: '#app-1',
            data: {
                msg: 'This is HELLO WORLD~!!!'

            },
            methods: {
                reversedByMethods : function() {
                    return this.msg.split('').reverse().join('');
                }
            },
            computed : {
                reversedByComputed: function(){
                    return this.msg.split('').reverse().join('');
                }
            }
        })
        app1.msg = 'try input below line in console';

        // < computed 속성 vs watch 속성 >
        //위에서 봤던 computed 속성은 소프트웨어 공학에서 이야기하는 '선언형 프로그래밍' 방식이라고 합니다.
        //반면 아래에서 보는 watch 속성은 '명령형 프로그래밍'이라고 합니다.
        //computed 속성 같은 선언형 프로그래밍 방식은 계산해야 하는 목표 데이터를 정의하는 방식입니다.
        //watch 속성과 같은 명령형 프로그래밍 방식은 감시할 데이터를 지정하고 그 데이터가 바뀌면 이런 함수를 실행하라는 방식입니다.
        //(역자 주: 일반적으로 선언형 프로그래밍이 명령형 프로그래밍보다 코드 반복이 적은 등 우수하다고 평가하는 경향이 있음.)
        var app2 = new Vue({
            el: '#app-2',
            data: {
                firstName: 'say',
                lastName: 'park',
                fullName:'say park'
            },
            watch: {
                firstName: function(val) {
                    console.log('passing throug watch > firstName');
                    this.fullName = val + ' ' + this.lastName;
                },
                lastName: function(val) {
                    console.log('passing throug watch > LastName');
                    this.fullName = this.firstName + ' ' + val;
                }
            }
        })

        // < watch 속성 활용 >
        //watch 속성 안에 question을 선언합니다. 즉, question 값을 감시하기로 합니다.
        //question 값이 바뀔 때마다 선언해 놓은 function() 을 실행합니다.
        //여기서는 data 속성의 answer 값을 '입력을 기다리는 중...'로 바꾸고 this.debouncedGetAnswer()를 실행합니다. 그게 question 값이 바뀔 때마다 실행할 함수입니다.
        //created 후크로 this.debouncedGetAnswer 안에 함수를 넣어 줍니다.
        //crated 후크에서는 초기값이 이미 다 들어간 뒤이기 때문에 methods 에 정의된 값들을 꺼내다 쓸 수 있습니다.
        //원래는 ajax 같은 거 써서 서버까지 다녀오는 처리가 있습니다. 이유는 watch 속성을 비동기식 처리에 사용하면 좋다는 걸 보여주기 위해서입니다. 여기서는 그냥 setTimeout 함수로 대체하겠습니다.
        var app3 = new Vue({
            el: '#app-3',
            data: {
                question: '',
                answer: '질문을 하기 전까지는 대답할 수 없습니다.'
            },
            watch: {
                // data 속성의 question 값이 변경될 때마다 이 기능이 실행됩니다.
                question: function (newQuestion) {
                    this.answer = '입력을 기다리는 중...'
                    this.debouncedGetAnswer()
                }
            },
            created: function () {
                this.debouncedGetAnswer = this.getAnswer
            },
            methods: {
                getAnswer: function () {
                    if (this.question.indexOf('?') === -1) {
                        this.answer = '질문에는 일반적으로 물음표가 포함 됩니다. ;-)'
                        return
                    }
                    this.answer = '생각중...'
                    setTimeout(() => {this.answer = "hello " + this.question;}, 3000);
                }
            }
        })

 

 

참고자료

https://kr.vuejs.org/v2/guide/computed.html

- 220421

반응형