일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- typeScript
- OOP
- 상속
- Zustand
- 객체지향프로그래밍
- 클래스
- 노마드코더
- 추상화
- 타입스크립트
- 부트캠프
- 패스트캠퍼스
- frontend
- JavaScript
- webdevelopment
- 프론트엔드
- 웹개발
- 투두앱만들기
- 자바스크립트
- Props
- 자바스트립트
- CSS
- 캡슐화
- js
- 논리연산자
- github
- 불변성
- REACT
- 리액트
- Hooks
- Fetch
- Today
- Total
connecting dots
Beginner 11회차 (8/13) | 화살표 함수와 코드 축약, store로 데이터 수정, 삭제 로직 옮기기, modal에 삭제 수정 기능 추가, promise(callback hell), useEffect(), 체크박스 기능 추가 본문
Beginner 11회차 (8/13) | 화살표 함수와 코드 축약, store로 데이터 수정, 삭제 로직 옮기기, modal에 삭제 수정 기능 추가, promise(callback hell), useEffect(), 체크박스 기능 추가
dearsuhyun 2024. 8. 14. 17:22화살표 함수

코드 축약


Main.tsx 파일에 있던 setTodo(), deleteTodo() 함수 store로 이사 시키기
데이터를 불러 오는 getTodos()를 store로 이동시켜주었기 때문에
투두 리스트를 새로 수정하는 setTodo(), 투두를 삭제하는 deleteTodo() 역시 store로 이사를 시켜야 한다 !
데이터 권한이 이제 Main -> store로 넘어간 상황이니 수정, 삭제하는 부분도 store에서 제어해줘야 한다.
기존 Main.tsx



store에서 가지고 올 수 있도록 TodoItem 파일 수정

옮긴 후 똑같이 작동하는 화면

모달에 삭제, 수정기능 추가
전체 코드
import styles from './TodoItemModal.module.css'
import { useNavigate, useParams } from 'react-router-dom'
import { useTodosStore } from '@/stores/todos'
import { useState } from 'react'
export default function TodoItemModal() {
const navigate = useNavigate() // 훅 꺼내서 사용할게
const { todoId } = useParams() // index.tsx에서 설정한 :todoId를 가져온다
const todos = useTodosStore(state => state.todos) // 배열
const deleteTodo = useTodosStore(state => state.deleteTodo)
const updateTodo = useTodosStore(state => state.updateTodo)
const currentTodo = todos.find(todo => todo.id === todoId) // 지금 id랑 주소창에 있는 id랑 같은 todo를 찾아서 가져온다
const [title, setTitle] = useState(currentTodo?.title || '')
const [done, setDone] = useState(currentTodo?.done || false)
function offModal() {
navigate('/') // 메인 페이지로 이동
}
function deleteCurrentTodo() {
if (currentTodo) {
deleteTodo(currentTodo)
offModal()
}
}
function updateCurrentTodo() {
if (currentTodo) {
updateTodo({
...currentTodo,
title
})
}
}
return (
<div className={styles.modal}>
<div
className={styles.overlay}
onClick={offModal}></div>
<div className={styles.contents}>
<div>{currentTodo?.title}</div>
<div>{currentTodo?.createdAt}</div>
<input
type="checkbox"
checked={done}
onChange={e => {
setDone(e.target.checked)
if (currentTodo) {
updateTodo({
...currentTodo,
done: e.target.checked
})
}
}}
/>
<input
value={title}
onChange={e => setTitle(e.target.value)}
/>
<button onClick={updateCurrentTodo}>수정</button>
<button onClick={deleteCurrentTodo}>삭제</button>
</div>
</div>
)
}
삭제 코드 뜯어보기
store에서 데이터 다루기 위해 useTodosStore 가지고 오기
// store
async function deleteTodo(deletedTodo: Todo) {
await fetch(
`https://asia-northeast3-heropy-api.cloudfunctions.net/api/todos/${deletedTodo.id}`, //:todoId
{
method: 'DELETE',
headers: {
'content-type': 'application/json',
apikey: 'KDT9_AHMq2s7n',
username: 'FE1_ParkSuHyun'
}
}
)
getTodos()
}
import { useTodosStore } from '@/stores/todos'
const todos = useTodosStore(state => state.todos) // 배열
const deleteTodo = useTodosStore(state => state.deleteTodo)
const currentTodo = todos.find(todo => todo.id === todoId)
// 지금 id랑 주소창에 있는 id랑 같은 todo를 찾아서 가져온다
버튼을 누르면 deleteCurrentTodo 함수 실행 --> 현재 todo를 지우는 로직 실행, offModal 함수로 메인페이지로 이동
function offModal() {
navigate('/') // 메인 페이지로 이동
}
function deleteCurrentTodo() {
if (currentTodo) { // 현재 todo
deleteTodo(currentTodo)
offModal()
}
}
return (
<button onClick={deleteCurrentTodo}>삭제</button>
)
수정 코드 뜯어보기
store에서 데이터 수정하기 위해 updateTodo가지고 오기
// store
async function updateTodo(updatedTodo: Todo) {
try {
await fetch(
`https://asia-northeast3-heropy-api.cloudfunctions.net/api/todos/${updatedTodo.id}`,
{
method: 'PUT',
headers: {
'content-type': 'application/json',
apikey: 'KDT9_AHMq2s7n',
username: 'FE1_ParkSuHyun'
},
body: JSON.stringify({
title: updatedTodo.title,
done: updatedTodo.done
})
}
)
getTodos()
} catch (error) {
console.error(error)
}
}
import { useTodosStore } from '@/stores/todos'
const updateTodo = useTodosStore(state => state.updateTodo)
const currentTodo = todos.find(todo => todo.id === todoId)
수정 버튼 누르면 updateCurrentTodo 함수 실행 --> currentTodo를 업데이트 된 todo로 바꿔줌
function updateCurrentTodo() {
if (currentTodo) {
updateTodo({
...currentTodo,
title
})
}
}
return (
<input
value={title}
onChange={e => setTitle(e.target.value)}
/>
<button onClick={updateCurrentTodo}>수정</button>
)
현재 수정 시 offModal을 사용하지 않아서 랜딩 페이지로 넘어가지 않지만 밑 코드처럼 추가해주면
삭제버튼 눌렀을 때와 같이 내용 수정과 랜딩 페이지로 돌아가게 구현됨 !
function updateCurrentTodo() {
if (currentTodo) {
updateTodo({
...currentTodo,
title
})
offModal()
}
}

--> 사실 useEffect()를 사용해서 todo가 변경될 때마다 title을 변경하도록 해주어야 위 구현 영상처럼 input 부분도 바뀐 todo의 title로 잘 반영될 수 있음 !
useEffect()
의존성 배열에 데이터를 넣으면, 데이터 변경 시 콜백함수가 실행됨 !

useEffect는 React에서 제공하는 훅(hook) 중 하나로, 함수형 컴포넌트가 렌더링될 때마다 특정 작업(사이드 이펙트)을 수행할 수 있게 해줍니다. 사이드 이펙트란 컴포넌트의 렌더링 외에 발생하는 모든 작업을 의미합니다. 예를 들어, 데이터를 가져오거나, 타이머를 설정하거나, 브라우저 API를 사용하는 작업 등이 사이드 이펙트입니다.
- 기본 구조
useEffect(() => { // 여기에 실행할 코드를 작성합니다. }, [의존성 배열]);
• 첫 번째 매개변수: 실행할 코드를 함수로 정의합니다. 이 함수가 컴포넌트가 렌더링될 때마다 실행됩니다.
• 두 번째 매개변수 (의존성 배열): 이 배열에 포함된 값들이 변경될 때만 useEffect 안의 함수가 실행됩니다. 배열이 비어 있으면, 컴포넌트가 처음 렌더링될 때 한 번만 실행됩니다.
- 예제
import React, { useState, useEffect } from 'react'; function ExampleComponent() { const [count, setCount] = useState(0); useEffect(() => { console.log(`count가 변경되었습니다: ${count}`); }, [count]); return ( <div> <p>{count}</p> <button onClick={() => setCount(count + 1)}>증가</button> </div> ); }
체크박스 만들기
// todoItemModal
const [done, setDone] = useState(currentTodo?.done || false)
return (
<input
type="checkbox"
checked={done}
onChange={e => {
setDone(e.target.checked)
if (currentTodo) {
updateTodo({
...currentTodo,
done: e.target.checked
})
}
}}
)
// todoItem
const [done, setDone] = useState(todo.done)
useEffect(() => {
setTItle(todo.title)
setDone(todo.done)
}, [todo])
return (
<input
type="checkbox"
checked={done}
onChange={e => {
setDone(e.target.checked)
updateTodo({
...todo,
done: e.target.checked
})
}}
/>
)

콜백지옥(callback hell)

--> 해결 방법 promise !
await의 경우에는 promise 인스턴스를 반환하는 함수 앞에만 붙일 수 있음 !
원래 promise 인스턴스를 반환하는 함수가 아니더라도 앞에 async 붙여주면 await 사용 가능
(async 키워드가 붙은 함수는 언제나 promise 인스턴스를 반환한다 !)
promise 생성자 함수에서는 무조건 resolve 호출을 해줘야 함


map 메소드: 새로운 배열 데이터(콜백에서 모아서) 반환
리팩토링: 코드 기능은 달라지지 않았지만 코드 내용은 바뀌는 것 (원래의 기능, 동작은 그대로 but 코드만 수정)
만약 새로운 기능이 생긴다면 ? --> 기능 개발 !
https://www.heropy.dev/p/N6phSt
JS 함수 핵심 패턴
자바스크립트 함수에 대한 기본적인 사용 방법부터 관련 용어, 고급 기법 등의 관련된 다양한 함수 패턴과 여러 개념을 살펴봅니다.
www.heropy.dev
https://www.heropy.dev/p/OidQSe
React 핵심 패턴
React 기본 문법의 다양한 사용 패턴을 살펴봅니다.
www.heropy.dev