본문 바로가기

근래의 javascript가 좋아진 이유 중 하나는 ajax와 더불어 실시간 데이터의 변화를 감지해서 바로바로 적용해 주는 것 입니다. vue.js도 그중에 하나라고 할 수 있습니다.
vue.js는 data로 선언된 객체변수를 computedgetters를 사용해서 조건에 부합하는 데이터를 실시간으로 filtering해서 가져올 수 있습니다. 예를들면 아래와 같습니다.

data() { 
    return { 
        todos: [
          { id: 1, name: '...', age: '...', sex: '...', done: false},
          { id: 2, name: '...', age: '...', sex: '...', done: true}
          { id: 3, name: '...', age: '...', sex: '...', done: false}
          { id: 4, name: '...', age: '...', sex: '...', done: false}
          { id: 5, name: '...', age: '...', sex: '...', done: true}
        ]
    }
},

computed: {
  doneTodos () {
      // todos 중에서 done이 true인 객체만 가져오기
    return this.todos.filter(todo => todo.done)
  }
}

computed에서 선언된 doneTodos변수는 script영역에서 this.doneTodos으로 실시간으로 변경된 값을 사용할 수 있고, html탬플릿 영역에서 <div v-for="doneTodo in doneTodos" :key="doneTodo.id"></div> 이런 식으로 사용할 수 있습니다.

data()에 선언된 todos의 값을 추가하거나 done변수의 값을 변경시키면 doneTodos의 값도 실시간 변경이 이루어 지게 되어 있습니다.

문제의 증상

그런데 문제는 의도와 다르게 이게 실시간 변경이 되지않고 미친(?) 치마바람 흔들리 듯이 지맘대로 변경되는 것이였습니다. 돌아버리는 줄 알았습니다.
todo의 할일이 끝나서 todoProcess()함수를 이용하여 done변수를 true로 변경을 해도 doneTodos에는 전혀 반응이 없습니다. 원래대로 라면 해당 todo 객체가 doneTodos리스트에도 나타나야 할텐데 나타나지가 않습니다.

문제의 원인

문제의 원인은 처음 해당 객체를 생성할 떄 해당 변수를 설정하지 않아서 발생한 문제 였습니다.
제가 작성한 망한 코드는 아래와 같습니다.
아무리 todos의 done의 값을 추가해도 doneTodos의 값이 변하지 않습니다.

data() { 
    return { 
        todos: [
          { id: 1, name: '...', age: '...', sex: '...'},
          { id: 2, name: '...', age: '...', sex: '...'}
          { id: 3, name: '...', age: '...', sex: '...'}
          { id: 4, name: '...', age: '...', sex: '...'}
          { id: 5, name: '...', age: '...', sex: '...'}
        ]
    }
},

 methods: {
    todoProcess function (todoDoneList) {
        this.todos.map((todo) => {
            if (todoDoneList.indexOf(todo.id) < 0) {
                todo.done = false;
            } else {
                todo.done = true;
            }
        });
    }
  },

computed: {
  doneTodos () {
    return this.todos.filter(todo => todo.done)
  }
}

문제의 해결

변경된 완성 코드는 아래와 같습니다.
중요한 것은 data()의 todos객체를 생성할 떄 done 변수를 미리 생성해 놔야 합니다. 그러면 정상 작동합니다. (다른 코드는 하나도 바뀐것이 없습니다.)

data() { 
    return { 
        todos: [
          { id: 1, name: '...', age: '...', sex: '...', done: false},
          { id: 2, name: '...', age: '...', sex: '...', done: false}
          { id: 3, name: '...', age: '...', sex: '...', done: false}
          { id: 4, name: '...', age: '...', sex: '...', done: false}
          { id: 5, name: '...', age: '...', sex: '...', done: false}
        ]
    }
},

 methods: {
    todoProcess function (todoDoneList) {
        this.todos.map((todo) => {
            if (todoDoneList.indexOf(todo.id) < 0) {
                todo.done = false;
            } else {
                todo.done = true;
            }
        });
    }
  },

computed: {
  doneTodos () {
    return this.todos.filter(todo => todo.done)
  }
}

쉽게 말해서 객체 변수의 변화 감시는 미리 세팅되어 있는 객체 변수에 한해서만 한다는 것입니다. 중간에 추가된 객체의 변수는 변화에 대한 인식을 하지 못합니다.

Vue메뉴얼에는 반응형이라고 하네요. 아래의 URL을 자세히 읽어보시면 도움이 되실 것입니다.

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

기타

만약 vuex를 사용한다면 computed 대신 getters도 동일한 방법으로 사용하면 됩니다.
vuex를 사용한다면 중앙에 store를 두고 프로젝트 전체에서 사용할 텐데요.
computed처럼 실시간으로 데이터를 변형해서 사용할 수 있게 해주는 것이 getters입니다.

로딩중

UX 공작소

고급지게 만들어 저렴하게 배포는 공작소