Vue.js

Vue.js 3.0 STEP 7 - TodoList 리팩토링

2024. 1. 25. 17:19
728x90

★ 컴포넌트 분할과 정의

  • 재사용성, 테스트 용이성, 디버깅 편의성 등을 고려해 컴포넌트를 분할하는 것을 권장하고 있다.
  • 한 번에 변경되는 데이터를 렌더링하는 UI 단위로 컴포넌트를 분할하는 편이 좋다.
  • 데이터가 변경되는 단위로 컴포넌트를 세분화하면 해당 컴포넌트만 다시 렌더링하고 나머지 컴포넌트는 다시 렌더링 하지 않게 되어 보다 좋은 렌더링 성능을 제공할 수 있게 된다.
  • 특히 반복 렌더링하는 부분은 반드시 별도의 컴포넌트로 작성하는것이 좋다.

 

■ 관리해야 할 데이터

  • todo는 InputTodo 컴포넌트의 로컬 데이터로 정의한다.
  • 왜냐하면, 데이터가 관리할 만큼 중요하지 않으므로 데이터의 생명주기 관리가 필요하지 않기 때문이다.
{
    todoList : [
    	{ id : 1, todo : "자전거 타기", completed : false },
        { id : 2, todo : "공원 산책", completed : true },
        { id : 3, todo : "일요일 애견 카페", completed : false },
        { id : 4, todo : "Vue 원고 집필", completed : false },
    ]
}

 

■ 메서드 정의

  • 메서드 목록
- addTodo(todo)
- deleteTodo(id)
- toggleCompleted(id)
  • 수신 이벤트 목록
- add-todo : 전달 인자-todo
- delete-todo : 전달 인자-id
- toggle-completed : 전달 인자-id
  • 컴포넌트 목록 
* App 컴포넌트
 - data : todoList 배열
 - methods : addTodo, deleteTodo, toggleCompleted 메서드
 - 수신 이벤트 : add-todo, delete-todo, toggle-completed

* InputTodo 컴포넌트
 - data : todo 문자열 값
 - 발신 이벤트 : add-todo
 
* TodoList 컴포넌트
 - props : todoList 배열(todoList)
 - 발신이벤트 : delete-todo(경유), toggle-completed(경유)
 - 수신이벤트 : delete-todo(경유), toggle-completed(경유)
 
* TodoListItem 컴포넌트
 - props : todoItem(todoList 배열의 값 하나)
 - 발신 이벤트 : delete-todo, toggle-completed

 

■ 프로젝트 생성

  • todolist-app 프로젝트 생성 
npm init vue todolist-app
cd todolist-app
npm install
npm install bootstrap@5

 

■ 기본 설정

  • main.js -> 변경
import { createApp } from 'vue'
import App from './App.vue'
import 'bootstrap/dist/css/bootstrap.css'
import './assets/main.css'

createApp(App).mount('#app')
  • src/assets/main.css -> 추가
body { margin : 0; padding : 0; font-family: sans-serif; }
.title { text-align: center; font-weight: bold; font-size: 20pt;}
.todo-done { text-decoration: line-through;}
.container { padding: 10px 10px 10px 10px; }
.panel-borderless { border : 0; box-shadow: none;}
.pointer {cursor: pointer;}

 

■ 코드 작성

  • src/App.vue 작성
<template>
  <div id="app" class="container">
    <div class="card card-body bg-light">
      <div class="title">:: Todolist App</div>
    </div>
    <div class="card card-default card-borderless">
      <div class="card-body">
        <InputTodo @add-todo="addTodo" />
        <TodoList :todoList="todoList" @delete-todo="deleteTodo"
          @toggle-completed="toggleCompleted" />
      </div>
    </div>
  </div>
</template>

<script>
import TodoList from './components/TodoList.vue'
import InputTodo from './components/InputTodo.vue'

let ts = new Date().getTime()

export default {
  name : "App",
  components : {InputTodo, TodoList},
  data() {
    return {
      todoList : [
        { id: ts, todo:"Vue 공부하기", completed: false },
        { id: ts+1, todo:"Vue 실습 하기", completed: false },
        { id: ts+2, todo:"Vue 프로젝트 하기", completed: false },
        { id: ts+3, todo:"Spring Boot 공부하기", completed: false },
      ]
    }
  },
  methods : {
    addTodo(todo) {
      if (todo.length >= 2) {
        this.todoList.push({ id : new Date().getTime(), todo: todo, completed : false});
      }
    },
    deleteTodo(id) {
      let index = this.todoList.findIndex((item) => id === item.id);
      this.todoList.splice(index, 1);
    },
    toggleCompleted(id) {
      let index = this.todoList.findIndex((item) => id === item.id);
      this.todoList[index].completed = !this.todoList[index].completed;
    }
  }
}
</script>
  • src/components/InputTodo.vue 작성
<template>
    <div class="row mb-3">
        <div class="col">
            <div class="input-group">
                <input id="msg" type="text" class="form-control" name="msg"
                    placeholder="할일을 여기에 입력하세요!" v-model.trim="todo"
                    @keyup.enter="addTodoHandler" />
                <span class="btn btn-primary input-group-addon"
                    @click="addTodoHandler">추가</span>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name : "InputTodo",
        data() {
            return { todo : "" }
        },
        emits : ["add-todo"],
        methods : {
            addTodoHandler() {
                if (this.todo.length >= 3) {
                    this.$emit('add-todo', this.todo);
                    this.todo = "";
                }
            }
        },
    }
</script>
  • src/components/TodoList.vue
<template>
    <div class="row">
        <div class="col">
            <ul class="list-group">
                <TodoListItem v-for="todoItem in todoList" :key="todoItem.id"
                    :todoItem="todoItem" @delete-todo="$emit('delete-todo', $event)"
                    @toggle-completed="$emit('toggle-completed', $event)" />
            </ul>
        </div>
    </div>
</template>

<script>
    import TodoListItem from './TodoListItem.vue'

    export default {
        name : "TodoList",
        components : { TodoListItem },
        props : {
            todoList : { type : Array, required:true }
        },
        emits : ["delete-todo", "toggle-completed"],
    }
</script>
  • src/components/TodoListItem.vue
<template>
    <li class="list-group-item"
        :class="{ 'list-group-item-success' : todoItem.completed }"
        @click="$emit('toggle-completed', todoItem.id)" >
        <span class="pointer" :class="{ 'todo-done' : todoItem.completed }">
            {{ todoItem.todo }} {{ todoItem.completed ? "(완료)" : "" }}
        </span>
        <span class="float-end badge bg-secondary pointer"
            @click.stop="$emit('delete-todo', todoItem.id)">삭제</span>
    </li>
</template>

<script>
    export default {
        name : "TodoListItem",
        props : {
            todoItem : { type : Object, required : true }
        },
        emits : [ "delete-todo", "toggle-completed"],
    }
</script>
  • 실행 결과

 

728x90
저작자표시 비영리 변경금지 (새창열림)

'Vue.js' 카테고리의 다른 글

Vue.js 3.0 STEP 6 - 단일 파일 컴포넌트  (2) 2024.01.25
Vue.js 3.0 STEP 5 - TodoList  (0) 2024.01.25
Vue.js 3.0 STEP 4 - 스타일 적용  (0) 2024.01.25
Vue.js 3.0 STEP 3 - 이벤트 처리  (0) 2024.01.18
Vue.js 3.0 STEP 2 - Vue 인스턴스  (0) 2024.01.18
'Vue.js' 카테고리의 다른 글
  • Vue.js 3.0 STEP 6 - 단일 파일 컴포넌트
  • Vue.js 3.0 STEP 5 - TodoList
  • Vue.js 3.0 STEP 4 - 스타일 적용
  • Vue.js 3.0 STEP 3 - 이벤트 처리
IT의 큰손
IT의 큰손
IT계의 큰손이 되고 싶은 개린이의 Log 일지
IT의 큰손
Developer Story House
IT의 큰손
전체
오늘
어제
  • 분류 전체보기 (457)
    • 정보처리기사 필기 (18)
    • 정보처리기사 실기 (12)
    • 정보처리기사 통합 QUIZ (12)
    • 빅데이터 (11)
    • 안드로이드 (11)
    • 웹페이지 (108)
    • 자바 (49)
    • SQLD (3)
    • 백준 알고리즘 (76)
    • 데이터베이스 (41)
    • 깃허브 (2)
    • Library (14)
    • Server (31)
    • 크롤링&스크래핑 (3)
    • Spring (23)
    • Vue.js (13)
    • React (27)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • Developer Stroy House

인기 글

태그

  • 웹개발
  • 코딩테스트
  • DBA
  • jsp
  • 웹페이지
  • it
  • DB
  • 프론트엔드
  • 웹개발자
  • 백엔드
  • 정보보안전문가
  • React
  • jquery
  • html
  • 개발블로그
  • 정보처리기사
  • 데이터베이스
  • 자바
  • java
  • ajax
  • JavaScript
  • 앱개발자
  • IT개발자
  • css
  • 정보처리기사필기
  • IT자격증
  • IT자격증공부
  • 백준
  • 개발자
  • 알고리즘

최근 댓글

최근 글

Designed By hELLO
IT의 큰손
Vue.js 3.0 STEP 7 - TodoList 리팩토링
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.