뷰 스터디를 진행하면서 검색기능을 추가하기로 했다.
처음엔 App.vue에 SearchTodo 컴포넌트를 추가하고 SearchTodo 컴포넌트에선 검색 input에 입력된 데이터를 dispatch를 통해 action으로 넘겨준 뒤 mutation에서 keyword를 넘겨받아 키워드를 filter메서드를 통해 걸러주기만 하면 된다고 생각했다.
SearchTodo.vue
<template>
<input type="text" class="w-100 p-2 mt-2"
placeholder="Search Todo!"
v-model="keyword" @input="searchTodo"/>
</template>
<script>
export default {
data(){
return{
keyword:''
}
},
methods:{
searchTodo(e){
this.$store.dispatch('todo/searchTodo',e.target.value)
}
}
}
</script>
Todo.js
SEARCH_TODO(state, keyword) {
if (keyword) {
const search = state.todos.filter(state.todos.text.include(keyword));
state.todos = search;
} else {
state.todos = [...state.todos];
}
},
},
하지만 이렇게 하게 된다면, 기존의 todos 데이터를 filter로 걸러진 데이터로 덮어씌워지기 때문에, 원본 데이터가 훼손되는 상황이 발생되었다.
그래서 원본 데이터를 훼손시키지 않고, filter로 걸러진 새로운 데이터를 보여줘야 한다고 생각했다.
state: {
todos: [
{ id: 1, text: "Buy a Car", checked: false },
{ id: 2, text: "Buy a Game", checked: false },
],
searchTodos: [],
},
위와 같이 serachTodos라는 새로운 배열을 만들고, 여기에 filter된 투두리스트를 담아주기로 했다.
SEARCH_TODO(state, keyword) {
if (keyword) {
const search = keyword.toLowerCase();
const result = state.todos.filter((todo) =>
todo.text.toLowerCase().includes(search)
);
state.searchTodos = result;
} else {
state.searchTodos = state.todos;
}
},
},
그리고 TodoList 컴포넌트에서 filter된 값을 보여주도록 했다.
하지만 TodoList에선 이미 기존의 todo데이터를 불러오고 있었기 때문에,
검색을 했을 때와 하지 않았을 때 List를 선택적으로 보여줘야 했는데, 컴포넌트 안에서 if문을 통해 계산을 해서 선택적으로 불러오는 건
코드가 너무 정돈되지 않는다고 생각했다.
현재는 Mutations에서 검색된 키워드로 filter만 해주는 메소드가 작성되어 있다.
이렇게 되면 결국 if문으로 검색 했을 때 or 하지 않았을 때 TodoList 데이터를 계산해줘야 했다.
그래서 store에 getters를 통해 미리 두 조건을 계산을 하고 이미 계산된 데이터만 TodoList 컴포넌트에서 불러와 List를 출력해주기로 했다.
검색 했을 때를 판단하기 위해
state: {
todos: [
{ id: 1, text: "Buy a Car", checked: false },
{ id: 2, text: "Buy a Game", checked: false },
],
searchTodos: [],
searchKeywords: false, //검색 유무 판단
},
serachKeywords를 boolean으로 선언 하였고
SEARCH_TODO(state, keyword) {
if (keyword) {
const search = keyword.toLowerCase();
const result = state.todos.filter((todo) =>
todo.text.toLowerCase().includes(search)
);
state.searchKeywords = true; //검색을 했을 때 true로 변경
state.searchTodos = result;
} else {
state.searchTodos = state.todos;
state.searchKeywords = false; // 검색을 하지 않았다면 false 유지
}
console.log(state.searchKeywords);
},
},
state.searchKeywords를 true와 false로 변경시켜주었다.
getters: {
numberOfCompletedTodo: (state) => {
return state.todos.filter((todo) => todo.checked).length;
},
searchTodos: (state) => {
if (state.searchKeywords) {
return state.searchTodos;
} else {
return state.todos;
}
},
그리고 getters에서 searchKeywords를 기준으로 true(검색 했을 때)라면 searchTodos(filter된 새로운 배열)을 반환해주고,
false(검색 X)라면 기존의 todos 리스트를 반환해주도록 했다.
<template>
<div>
<Todo v-for="todo in searchTodos"
:key="todo.id"
:todo="todo"/>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import Todo from './Todo.vue';
export default {
components: { Todo },
computed:{
...mapGetters('todo',['searchTodos']),
}
}
computed에 vuex helper를 통해 getters의 값을 가져와 Todo 컴포넌트에 v-for문으로 searchTodos의 값을 리스트로 출력해주었다.
성공적으로 검색이 되는 모습이다.
어떤 블로그에선 helper로 state가 아닌 다른 데이터를 가져오게 되는 경우엔 helper를 사용함에 있어서 편리함은 있지만, 내가 어떤 데이터를 가져오는지 가독성이 떨어져 좋지 않다고 하더라..
마지막으로
처음에 vue의 기본 구조를 배울 땐 React보다 쉽다고 느꼈는데 component와 부모 자식간 props를 전달하는 부분부터 더 어려워 졌다.
store를 통해 데이터를 저장하고 가져오는 부분도 번거롭게 느껴지기도 하는데 아직은 미숙하기 때문이 아닐까 생각한다.
현재 내가 작성한 코드가 많이 중구난방인 느낌이 강하다. 너무 데이터를 쓸데없이 주고받는 것 같고, 계산식 또한 복잡하다고 생각한다.
filter의 사용법이나 vuex의 구조를 많이 익혀야겠다.
'Vue.Js' 카테고리의 다른 글
[Vue.js]동적 라우팅 (3) | 2024.09.10 |
---|