목표
- useFetch()로 서버 데이터 가져오기
- watch()를 사용해 서버 데이터 변경 감지하기
- $fetch 사용해 HTTP 메서드 사용하기 (GET, POST, DELETE)
- 서버 데이터를 등록순/최신순 정렬하기
결과 화면
버전
node v.20.8.1
nuxt v.3.8.1
vue v.3.3.8
1. Nest.js + PSQL (백앤드 + 데이터베이스)
https://jae-study.tistory.com/80
Nest.js와 Psql을 사용해서 백앤드와 데이터베이스를 만들었다.
직접 백앤드와 데이터베이스를 만들어도 되고,
JSONPlaceholder 사이트를 통해 가짜 데이터를 받아와도 된다.
2. toDo 가져오기
- pages/index.vue
Nuxt3에서는 axios 대신 useFetch()를 사용해 데이터 패칭을 한다.
useFetch()는 데이터를 비동기적으로 불러올 수 있고, 기존 axios 코드보다 로직을 간소화할 수 있다.
https://jae-study.tistory.com/127
useFetch()에 대한 자세한 설명은 위의 링크를 참고한다.
- Nuxt3는 타입스크립트 기반이기 때문에 useFetch()로 받아오는 데이터의 타입을 정의한다. (IToDo[])
- 서버에서 받은 데이터를 가공하기 위해 toDoData 변수를 만든다. useFetch()로 받아오는 데이터의 타입은 기본적으로 객체(object)이다. 이것을 배열로 만들어 정렬(sort 메서드)을 하고 싶어 toDoData 변수를 만들었다.
- toDo를 추가하고 삭제할 때마다 실시간으로 렌더링 하기 위해 watch 함수를 사용한다.
<script setup lang="ts">
interface IToDo {
id: number
todo: string
created_at: Date
}
// axios.get 기능 (toDo 가져오기)
const { data, refresh } = await useFetch<IToDo[]>('http://localhost:3001/todo')
const toDoData = ref(data.value ? [...data.value] : [])
watch(() => data.value, () => {
toDoData.value = isActive.value ? [...data.value] : [...data.value].reverse()
})
...
</script>
3. toDo 추가하기
- pages/index.vue
- newToDo 변수를 만들어 빈 값이면 alert() 창이 나오게 하고, 값이 있으면 POST 메서드를 실행한다.
- POST가 완료되면 newToDo를 빈 값으로 만들고, 실시간 값 변화를 감지하기 위해 refresh()를 실행한다.
<script setup lang="ts">
const newToDo = ref('')
// axios.post 기능 (toDo 추가하기)
async function addToDo() {
if(newToDo.value === '') {
alert('할 일을 입력해 주세요.')
} else {
await $fetch('http://localhost:3001/todo', {
method: 'POST',
body: { todo: newToDo.value }
})
newToDo.value = ''
await refresh()
}
}
...
</script>
4. toDo 삭제하기
- pages/index.vue
- 리스트 1개만 삭제하고 싶으면 해당하는 id 값을 매개변수로 받아 DELETE 메서드를 실행한다.
- 리스트 전체를 삭제하고 싶으면 api 전체 리스트에서 DELETE 메서드를 실행한다.
- DELETE가 완료되면 실시간 값 변화를 감지하기 위해 refresh()를 실행한다.
<script setup lang="ts">
// axios.delete 기능 (toDo 삭제하기)
async function deleteToDo(id: number) {
await $fetch(`http://localhost:3001/todo/${id}`, {
method: 'DELETE'
})
await refresh()
}
// axios.delete 기능 (toDo 전체 삭제하기)
async function clearToDo() {
if(window.confirm('리스트를 모두 삭제하시겠습니까?')) {
await $fetch(`http://localhost:3001/todo`, {
method: 'DELETE'
})
await refresh()
}
}
...
</script>
5. toDo 정렬하기
- pages/index.vue
- useFetch()로 받은 데이터를 배열로 만들어 sort() 메서드를 사용해 등록순/최신순으로 정렬한다.
<script setup lang="ts">
const isActive = ref(true)
// 등록순, 최신순 정렬하기
function sortToDo(compareFn: (a: IToDo, b: IToDo) => number) {
toDoData.value = [...data.value].sort(compareFn)
isActive.value = !isActive.value
}
...
</script>
<template>
<section class="w-full max-w-screen-lg min-h-screen m-auto">
...
<div v-if="toDoData.length > 0">
<div class="flex gap-2 mb-6">
<button
:class="{ 'underline underline-offset-4' : isActive }"
@click="() => sortToDo((a, b) => a.id - b.id)">
등록순
</button>
<i>|</i>
<button
:class="{ 'underline underline-offset-4' : !isActive }"
@click="() => sortToDo((a, b) => b.id - a.id)">
최신순
</button>
</div>
</div>
...
</section>
</template>
6. 마크업
- pages/index.vue
- 테일윈드를 사용해 CSS를 작성했다.
- 각각의 버튼에 맞는 @click 이벤트를 작성한다.
<template>
<section class="w-full max-w-screen-lg min-h-screen m-auto">
<h1 class="mt-6 mb-12 md:mt-10 text-5xl font-bold text-center">To Do List</h1>
<form
class="mb-6"
@submit.prevent="addToDo()">
<label
for="toDo"
class="block mb-3 text-xl font-bold">
New To Do
</label>
<div class="flex gap-3 md:gap-5">
<input
v-model="newToDo"
type="text"
id="toDo"
class="w-3/4 px-3 py-4 rounded outline-none text-black"
placeholder="할 일을 입력해 주세요."/>
<button class="w-1/4 bg-teal-600 hover:bg-teal-500 transition rounded">추가하기</button>
</div>
</form>
<div v-if="toDoData.length > 0">
<div class="flex gap-2 mb-6">
<button
:class="{ 'underline underline-offset-4' : isActive }"
@click="() => sortToDo((a, b) => a.id - b.id)">
등록순
</button>
<i>|</i>
<button
:class="{ 'underline underline-offset-4' : !isActive }"
@click="() => sortToDo((a, b) => b.id - a.id)">
최신순
</button>
</div>
<ul>
<li
v-for="(data, key) in toDoData"
:key="key"
class="flex justify-between items-center gap-3 mb-6 px-4 py-3 md:px-5 border rounded">
<p class="flex gap-2 text-base md:text-lg">
<span>{{ key + 1 }}.</span> {{ data.todo }}
</p>
<button
class="min-w-fit px-5 py-2 bg-teal-600 hover:bg-teal-500 transition rounded"
@click="deleteToDo(data.id)">
삭제
</button>
</li>
</ul>
<button
class="block w-full md:w-1/3 m-auto mt-12 px-3 py-4 bg-teal-950 hover:bg-teal-500 transition rounded"
@click="clearToDo()">
전체 삭제하기
</button>
</div>
</section>
</template>
상세 코드는 깃허브 페이지를 참고한다.
https://github.com/heejae0811/nuxt3-todo/tree/axios
'Vue, Nuxt > Nuxt 3 ToDo 만들기' 카테고리의 다른 글
[Nuxt3] #7 ToDo List 만들기 - Nest.js + PSQL 상세페이지 만들기 (useFetch()) (1) | 2023.12.26 |
---|---|
[Nuxt3] #5 ToDo List 만들기 - meta 태그 추가하기 (0) | 2023.11.30 |
[Nuxt3] #4 ToDo List 만들기 - 깃허브 페이지 배포하기 (0) | 2023.11.30 |
[Nuxt3] #3 ToDo List 만들기 - 등록순/최신순 정렬하기 (0) | 2023.11.30 |
[Nuxt3] #2 ToDo List 만들기 - Pinia store로 ToDo 추가, 삭제하기 (0) | 2023.11.29 |