개발

CRUD란?

비니_ 2025. 9. 16. 15:40
728x90

 

 

C 새로운 데이터 생성

R 데이터 조회

U 기존 데이터 수정

D 데이터 삭제

 

  C = Creat = POST
  R = Read = GET
  U = Update = PUT(전체 데이터 교체) / UPDATE(일부만 수정)
  D = Delete = DELETE

 

예시)

POST /posts → 게시글 작성

GET /posts → 게시글 목록 조회

GET /posts/1 → 1번 글 조회

PUT /posts/1 → 1번 글 전체 수정

PATCH /posts/1 → 1번 글 일부 수정

DELETE /posts/1 → 1번 글 삭제

 

 

테스트 코드

"use client";

import { useEffect, useState } from "react";

interface User{
    id: number;
    name: string;
}

export default function UserCrud(){
    const [users, setUsers] = useState<User[]>([
        { id: 1, name: "유저1" },
        { id: 2, name: "유저2" },
    ]);

    const [newName, setNewName] = useState<string>("");

    // creat 함수
    const addUser = () => {
        if( !newName.trim()) return; // 빈값 방지
        const newUser: User = {
            id: users.length ? users[users.length - 1].id + 1 : 1,
            name: newName,
        };
        setUsers([...users, newUser]);
        setNewName(""); // 입력창 초기화
    }

    // update 함수
    const updateUser = (id: number) => {
        const updatedName = prompt("새 이름 입력: ");
        if(!updatedName) return;
        setUsers(prev =>
            prev.map(user => (user.id === id ? { ...user, name: updatedName } : user))
        );
    };

    // delete 함수
    const deleteUser = (id: number) => {
        setUsers(prev => prev.filter(user => user.id !== id));
    };

    useEffect(() => {
        console.log('===users 데이터 내용==================================');
        console.log(users);
    }, [users])

    return(
        <div>
            <h2>사용자 목록</h2>
            <ul>
                {users.map(user => (
                    <li key={user.id}>
                        {user.id} - {user.name}
                    </li>
                ))}
            </ul>

            <input
                type="text"
                placeholder="이름을 입력하세요"
                value={newName}
                onChange={e => setNewName(e.target.value)}
            />
            <button onClick={addUser}>추가</button>
            {users.map(user => (
                <li key={user.id}>
                    {user.id} = {user.name}
                    <button onClick={() => updateUser(user.id)}>수정</button>
                    <button onClick={() => deleteUser(user.id)}>삭제</button>
                </li>
            ))}
        </div>
    )
}

 

💻 방어코드

✔ if( !newName.trim()) return;

// 빈값이 들어오면 함수 종료, 방어 코드

// null, undefined, " " 걸러줌

 

✔ if(!updatedName) return;

// 빈 값일 때 확인 누르면 함수 종료, 방어코드

=> 공백도 방어하려면 trim() 사용

if(!updatedName.trim()) return;

 

 

객체에 birth라는 속성 추가할 경우

수정된 부분 💛 표시

"use client";

import { useEffect, useState } from "react";

interface User{
    id: number;
    name: string;
    birth: string; 💛
}

export default function UserCrud(){
    const [users, setUsers] = useState<User[]>([
        { id: 1, name: "유저1", birth: '2025.02.10' }, 💛
        { id: 2, name: "유저2", birth: '1996.10.01' }, 💛
    ]);

    const [newName, setNewName] = useState<string>("");
    const [newBirth, setNewBirth] = useState<string>(""); 💛

    // creat 함수
    const addUser = () => {
        if( !newName.trim()) return; // 빈값이 들어오면 함수 종료, 방어 코드 // null, undefined, " " 걸러줌
        const newUser: User = {
            id: users.length ? users[users.length - 1].id + 1 : 1,
            name: newName,
            birth: newBirth 💛
        };
        setUsers([...users, newUser]);
        setNewName(""); // 입력창 초기화
        setNewBirth(""); 💛
    }

    // update 함수 💛
    const updateUser = (id: number) => {
        // 이름 수정
        const updatedName = prompt("수정할 이름 입력, 치소시 기존 값 유지");

        // 생일 수정
        const updatedBirth = prompt("수정할 생일 입력, 취소시 기존 값 유지 ");

        setUsers(prev =>
            prev.map(user => (user.id === id
                ? { ...user,
                    name: updatedName?.trim() || user.name, // 옵셔널이 없으면 빨간줄 나는 이유 => prompt가 string|null을 반환하기 때문에 null일 경우 타입이 안맞아서 빨간줄이 뜸
                    birth: updatedBirth?.trim() || user.birth
                }
                : user))
        );
    };

    // delete 함수
    const deleteUser = (id: number) => {
        setUsers(prev => prev.filter(user => user.id !== id));
    };

    useEffect(() => {
        console.log('===users 데이터 내용==================================');
        console.log(users);
    }, [users])

    return(
        <div>
            <h2>사용자 목록</h2>
            <ul>
                {users.map(user => (
                    <li key={user.id}>
                        {user.id} - {user.name} - {user.birth}
                    </li>
                ))}
            </ul>

            <label htmlFor="">이름</label>
            <input
                type="text"
                placeholder="이름을 입력하세요"
                value={newName}
                onChange={e => setNewName(e.target.value)}
            />
            <br />
            <label htmlFor="">생일</label>
            <input
                type="text"
                placeholder="ex) 2000.01.01"
                value={newBirth}
                onChange={e => setNewBirth(e.target.value)}
            /> 💛
            <button onClick={addUser}>추가</button>
            {users.map(user => (
                <li key={user.id}>
                    {user.id} = {user.name}
                    <button onClick={() => updateUser(user.id)}>수정</button>
                    <button onClick={() => deleteUser(user.id)}>삭제</button>
                </li>
            ))}
        </div>
    )
}

 

💻 prompt() 는 값을 string | null 반환

 

✔ name: updatedName?.trim() || user.name, 

// 옵셔널이 없으면 빨간줄 나는 이유

=> prompt가 string|null을 반환하기 때문에 null일 경우 타입이 안맞아서 빨간줄이 뜸

=> trim() 같은 문자열 메서드는 string 타입에서만 호출 가능

 

➰ 이해 돕기

prompt() 반환 → string | null
      │
      ▼
사용자가 값 입력 → string → trim() OK ✅
사용자가 취소 → null → trim() X ❌
      │
      ▼
옵셔널 체이닝 사용: updatedName?.trim()
  - null이면 undefined 반환 → 안전
  - string이면 trim() 실행 → 정상

 

 

 

728x90