deep watch

deep watch

감시자를 이용하다 보면 객체나 배열을 감시해야 하는 경우가 발생한다. 이 때 일반적인 감시자를 이용하면 정상적으로 감시가 이루어지지 않는 상황이 발생한다.

아래의 예제를 통해 확인한다.

<!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 deep watch</title>
    <style>
        * {
            box-sizing: border-box;
            font-size: 15px;
        }
        textarea{
            resize: none;
            padding:0.5em;
        }
        input{
            padding:0.5em;
        }
    </style>
</head>
<body>
    <div id="app">
        <label>
            title<br>
            <input type="text" v-model="board.title">
        </label>
        <br><br>

        <label>
            content<br>
            <textarea v-model="board.content" cols="50" rows="5"></textarea>
        </label>
        <br><br>
        revision count : {{revision}}
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    board:{
                        title:"Welcome to Vue JS 3!",
                        content:"VueJS는 사용자 인터페이스를 만들기 위한 progressive framework 입니다."
                    },
                    revision:0
                };
            },
            watch:{
                // not working
                board:function(){
                    this.revision++;
                }
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

data에 board라는 이름의 객체가 존재하며, 객체 안에는 title과 content라는 세부 항목이 존재한다.

data(){
    return {
        board:{
            title:"Welcome to Vue JS 3!",
            content:"VueJS는 사용자 인터페이스를 만들기 위한 progressive framework 입니다."
        },
        revision:0
    };
},

입력창은 객체가 아니라 객체 안의 항목인 title, content에 연결되어 있다.

<input type="text" v-model="board.title">
<textarea v-model="board.content" cols="50" rows="5"></textarea>

이 경우 객체의 내부 값이 변했다고 해서 객체가 변했다고 할 수 있을까? 그렇지 않다. 사람의 경우도 이름을 바꾼다고 해서 다른 사람이 되지 않듯이 객체도 내부의 값이 변경되었다고 해서 객체가 변화했다고 볼 수 없다. 따라서 일반적인 감시자로는 변화를 감지해낼 수 없다.

사용법

내용물의 변화까지도 감시자로 감지하고 싶은 경우 사용할 수 있는 것이 깊은 감시(deep watch)이다.

깊은 감시는 다음과 같이 객체형태로 설정한다.

watch:{
    항목명:{
        deep:true,
        handler(v, p){

        }
    }
},

사용 예제 - 깊은 감시 적용

<!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 deep watch</title>
    <style>
        * {
            box-sizing: border-box;
            font-size: 15px;
        }
        textarea{
            resize: none;
            padding:0.5em;
        }
        input{
            padding:0.5em;
        }
    </style>
</head>
<body>
    <div id="app">
        <label>
            title<br>
            <input type="text" v-model="board.title">
        </label>
        <br><br>

        <label>
            content<br>
            <textarea v-model="board.content" cols="50" rows="5"></textarea>
        </label>
        <br><br>
        revision count : {{revision}}
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    board:{
                        title:"Welcome to Vue JS 3!",
                        content:"VueJS는 사용자 인터페이스를 만들기 위한 progressive framework 입니다."
                    },
                    revision:0
                };
            },
            watch:{
                // not working
                // board:function(){
                //     this.revision++;
                // },

                // deep watch
                board:{
                    deep:true,
                    handler(){
                        this.revision++;
                    }
                }
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

실행해보면 정상적으로 잘 감시가 되는 것을 확인할 수 있다.

immediate

감시자 객체에 immediate 속성을 설정하면 Vue instance 실행 후 최초 1회는 대상의 변화가 없어도 실행된다.

<!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 deep watch</title>
    <style>
        * {
            box-sizing: border-box;
            font-size: 15px;
        }
        textarea{
            resize: none;
            padding:0.5em;
        }
        input{
            padding:0.5em;
        }
    </style>
</head>
<body>
    <div id="app">
        <label>
            title<br>
            <input type="text" v-model="board.title">
        </label>
        <br><br>

        <label>
            content<br>
            <textarea v-model="board.content" cols="50" rows="5"></textarea>
        </label>
        <br><br>
        revision count : {{revision}}
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return {
                    board:{
                        title:"Welcome to Vue JS 3!",
                        content:"VueJS는 사용자 인터페이스를 만들기 위한 progressive framework 입니다."
                    },
                    revision:0
                };
            },
            watch:{
                // not working
                // board:function(){
                //     this.revision++;
                // },

                // deep watch
                board:{
                    deep:true,
                    immediate:true,
                    handler(){
                        this.revision++;
                    }
                }
            }
        });
        app.mount("#app");
    </script>
</body>
</html>

Last updated