근래의 javascript가 좋아진 이유 중 하나는 ajax와 더불어 실시간 데이터의 변화를 감지해서 바로바로 적용해 주는 것 입니다. vue.js도 그중에 하나라고 할 수 있습니다.
vue.js는 data로 선언된 객체변수를 computed
나 getters
를 사용해서 조건에 부합하는 데이터를 실시간으로 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을 자세히 읽어보시면 도움이 되실 것입니다.
기타
만약 vuex를 사용한다면 computed
대신 getters
도 동일한 방법으로 사용하면 됩니다.
vuex를 사용한다면 중앙에 store
를 두고 프로젝트 전체에서 사용할 텐데요.
computed
처럼 실시간으로 데이터를 변형해서 사용할 수 있게 해주는 것이 getters
입니다.