본문 바로가기
코딩 프로그래밍/Javascript 자바스크립트

Vue 파일 분리할 때 필요한 emit

by 프즈 2023. 4. 4.
반응형

App.vue 파일에서 모두 작업하려면 너무 커지는데요. 모듈화 하여 분리할 수 있으면 다른 파일로 분리하여 나중에 코드를 파악하기도 좋게 하는 것이 좋은데요. 화면만 있다면 상관없는데 서로 데이터를 주고받아야 할 때 파일 하나로 작성하면 문제없던 일들이 분리하면서 알아야 하는 것들이 있어요.

vue create 명령어로 프로젝트를 시작했다면 components 폴더가 있고 HelloWorld.vue 파일도 예제로 있을 수 있어요. 살펴보는 것도 파악하는 과정에서 도움 받을 수 있어요. 일단 필요 없다면 지우고 원하는 파일을 추가합니다. TodoForm.vue 파일을 생성했습니다. 가장 기본 모양으로 만들어보고 App.vue 파일에서 불러와보세요.

<template>
    TO DO
</template>

<script>
export default {}
</script>

파일을 만들고 나서 App.vue에서 불러와 사용해야 합니다.

import TodoForm from './components/TodoForm.vue'

export default 부분에 components를 추가하여 그 안에 넣어줘야 합니다.

export default {
  components: {
    TodoForm
  },
  setup() {
  ...
  ...

이렇게 추가하고 나면 template 영역에서 사용 가능합니다. 태그처럼 불러올 수 있어요.

<TodoForm />

파일을 분리 했을 때 setup 하는 과정에서 props와 emit을 인수로 받을 수 있어요. emit을 이용해서 호출하는 쪽으로 데이터를 전송할 수 있어요. 

export default {
    setup(props, context) {        
        const todo = ref("")
        const errorMessage = ref("")

        const onAdd = () =>  {
            if(todo.value === ''){
                errorMessage.value = "아무것도 입력하지 않았습니다."       
            } else {
                context.emit("add-todo",{
                    id: Date.now(),
                    completed: false,
                    subject: todo.value
                })                
            todo.value = ""
            errorMessage.value = ""
          }
        }

        return {
            errorMessage,
            todo,
            onAdd
        }

    }
}

호출하는 쪽에서는 emit 첫 번째 인수에 있었던 것으로 함수 이름을 전달할 수 있어요.

<TodoForm @add-todo="onAdd" />

오류가 있는지는 모듈화한 파일에서 하고 있으니 onAdd 함수는 간단하게 작성할 수 있어요.

const onAdd = (todo) => todos.value.push(todo)

최종 코드입니다.

TodoForm.vue

<template>
    <h2>TO DO</h2>    
    <form 
      @submit.prevent="onAdd"
      class="d-flex"
    >
      <div class="flex-grow-1 mr-1">
        <input 
          class="form-control" 
          type="text"
          v-model="todo"
          placeholder="할일을 입력하세요."
        />
      </div>
      <div>
        <button
          class="btn btn-primary"
          type="submit"          
        >
          추가
        </button>
      </div>
    </form>    
    <div v-show="errorMessage!==''" class="card mt-10">
      <div class="card-body p-2">
        {{ errorMessage }}
      </div>
    </div>
</template>

<script>
import { ref } from 'vue'

export default {
    setup(props, context) {        
        const todo = ref("")
        const errorMessage = ref("")

        const onAdd = () =>  {
            if(todo.value === ''){
                errorMessage.value = "아무것도 입력하지 않았습니다."       
            } else {
                context.emit("add-todo",{
                    id: Date.now(),
                    completed: false,
                    subject: todo.value
                })                
            todo.value = ""
            errorMessage.value = ""
          }
        }

        return {
            errorMessage,
            todo,
            onAdd
        }

    }
}
</script>

App.vue

<template>
  <div class="container">    
    <TodoForm @add-todo="onAdd" />        
    <div
      v-for="(todo, index) in todos"
      :key="todo.id"      
      class="card mt-10"
    >
      <div class="card-body p-2 d-flex align-items-center">
        <div class="form-check flex-grow-1">
          <input class="form-check-input" type="checkbox" v-model="todo.completed"/>
          <label class="form-check-label" :class="{ todo: todo.completed }">
            {{ todo.subject }}
          </label>
        </div>
        <div>
          <button class="btn btn-danger btn-sm" @click="deleteTodo(index)">삭제</button>
        </div>
      </div>
    </div>
  </div>  
</template>

<script>
import { ref } from 'vue'
import TodoForm from './components/TodoForm.vue'
export default {
  components: {
    TodoForm
  },
  setup() {        
    const todos = ref([])    
    const todoCompletedStyle = {
      textDecoration: 'line-through',
      color: 'gray'
    }

    const onAdd = (todo) => todos.value.push(todo)             
        
    const deleteTodo = (index) => {      
      todos.value.splice(index,1)
    }

    return {
      todos,  
      todoCompletedStyle,
      onAdd,
      deleteTodo
    }
  }
}
</script>

<style scoped>
.todo {
  text-decoration: line-through;
  color: gray;
}
</style>
반응형

댓글