| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- MediaQuery
- minwidth
- owlcarousel
- legacy-peer
- 그누보드반응형
- 이미지반응형
- vscode git clone
- Git clone
- 정적객체
- fontawesome
- slickslider
- 웹아이콘
- 단어단위로떨어지기
- 아이콘사용법
- npm install
- npm install 문제
- maxwidth
- XEIcon
- git lab clone
- node설치
- 동적객체
- react npm install
- npm start
- googleicon
- package.json
- node 오류
- 의존성문제
- 플러그인
- window 정책변경
- 글자들여쓰기
- Today
- Total
어쩌다 알게 된 ƪ(•̃͡•̃͡ ƪ
오류 검증 본문
Enter시 초점 이동, 함수 실행
CRUD란?C 새로운 데이터 생성R 데이터 조회U 기존 데이터 수정D 데이터 삭제 C = Creat = POST R = Read = GET U = Update = PUT(전체 데이터 교체) / UPDATE(일부만 수정) D = Delete = DELETE 예시)POST /posts → 게시글 작
dazzle-bini.tistory.com
👆 이전 코드 이어서 사용
+ input 값 오류 검증, birth 속성 값 0000.00.00 타입으로 변경 업데이트
💻😥 맨 처음 짠 코드
// creat 함수
const addUser = () => {
const birthRegex = newBirth.replace(/\D/g, ""); // 숫자만 추출
// null, undefined, " " + 생일 입력 오류
if(!newName.trim() && birthRegex.length !== 8){
alert("이름을 입력해 주세요. \n 생일은 숫자 8자리로 입력해주세요.");
nameRef.current?.focus();
return;
}
if(!newName.trim()){
alert("이름을 입력해주세요");
nameRef.current?.focus();
return;
}
if(birthRegex.length !== 8){
alert("생일은 숫자 8자리로 입력해주세요. ex) 19880101");
birthRef.current?.focus();
return;
}
// 숫자 0000.00.00 형식으로 변환
const formattedBirth = `${birthRegex.slice(0, 4)}.${birthRegex.slice(4, 6)}.${birthRegex.slice(6, 8)}`;
const newUser: User = {
id: users.length ? users[users.length - 1].id + 1 : 1,
name: newName,
birth: formattedBirth,
};
setUsers([...users, newUser]);
setNewName(""); // 입력창 초기화
setNewBirth("");
}
💻😊 수정 코드
수정된 부분 💛 표시
// creat 함수
const addUser = () => {
const birthRegex = newBirth.replace(/\D/g, ""); // 숫자만 추출
if(!newName.trim() || birthRegex.length !== 8){ 💛
if(!newName.trim() && birthRegex.length !== 8){
alert("이름을 입력해주세요.\n생일은 숫자 8자리로 입력해주세요. ex) 19880101");
}else if(!newName.trim()){
alert("이름을 입력해주세요");
}else{
alert("생일은 숫자 8자리로 입력해주세요. ex) 19880101");
}
// 포커스
if(!newName.trim()) nameRef.current?.focus();
else birthRef.current?.focus();
return;
}
// 숫자 0000.00.00 형식으로 변환
const formattedBirth = `${birthRegex.slice(0, 4)}.${birthRegex.slice(4, 6)}.${birthRegex.slice(6, 8)}`;
const newUser: User = {
id: users.length ? users[users.length - 1].id + 1 : 1,
name: newName,
birth: formattedBirth,
};
setUsers([...users, newUser]);
setNewName(""); // 입력창 초기화
setNewBirth("");
}
=> 개별 적이던 조건물을 하나의 if로 크게 묶어서 중복 코드 줄이기
💻 정규식 사용
✔ const birthRegex = newBirth.replace(/\D/g, ""); // 숫자만 추출
💻 ref 사용
✔ birthRef.current?.focus(); // 포커스 이동
=> birthRef .current → <input> DOM 객체를 뜻함
💻 slice로 형식 변환
const formattedBirth = `${birthRegex.slice(0, 4)}.${birthRegex.slice(4, 6)}.${birthRegex.slice(6, 8)}`;
=> slice(start, end)는 문자열에서 start ~ end-1까지 잘라냄.
=> birthRegex.slice(0, 4)} : 0~4 자리수 추출
update 함수도 수정
+ 생일 값 검증
// update 함수
const updateUser = (id: number) => {
// 이름 수정
const updatedName = prompt("수정할 이름 입력, 취소시 기존 값 유지");
let formattedBirth: string | null = null;
let birthOnlyDigits: string | null = null;
// 생일 수정 및 검증
while (true) {
const updatedBirth = prompt("수정할 생일 입력 (숫자 8자리), 취소시 기존 값 유지");
if (!updatedBirth) break; // 취소 누르면 종료
// 숫자만 추출
birthOnlyDigits = updatedBirth.replace(/\D/g, "");
if (birthOnlyDigits.length === 8) {
formattedBirth = `${birthOnlyDigits.slice(0, 4)}.${birthOnlyDigits.slice(4, 6)}.${birthOnlyDigits.slice(6, 8)}`;
break; // 올바르면 변환하고 루프 종료
} else {
alert("생일은 숫자 8자리로 입력해주세요. ex) 19880101");
// while 계속 → prompt 다시 뜸
}
}
setUsers(prev =>
prev.map(user => (user.id === id
? { ...user,
name: updatedName?.trim() || user.name, // 옵셔널이 없으면 빨간줄 나는 이유 => prompt가 string|null을 반환하기 때문에 null일 경우 타입이 안맞아서 빨간줄이 뜸
birth: formattedBirth?.trim() || user.birth
}
: user)
)
);
};
💻 while(true) 사용 => 무한 루프
✔ 생일 검증이 틀렸을 경우, prompt가 다시 뜨게 하기 위해서 while 사용
✔ 안에 break가 없으면 무한 반복 됨
전체 코드
"use client";
import { useEffect, useRef, 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>("");
// 포커스 이동
const nameRef = useRef<HTMLInputElement>(null); // HTMLInputElement는 타입때문에 기입
const birthRef = useRef<HTMLInputElement>(null);
const birthRegex = newBirth.replace(/\D/g, ""); // 숫자만 추출
// creat 함수
const addUser = () => {
if(!newName.trim() || birthRegex.length !== 8){
if(!newName.trim() && birthRegex.length !== 8){
alert("이름을 입력해주세요.\n생일은 숫자 8자리로 입력해주세요. ex) 19880101");
}else if(!newName.trim()){
alert("이름을 입력해주세요");
}else{
alert("생일은 숫자 8자리로 입력해주세요. ex) 19880101");
}
// 포커스
if(!newName.trim()) nameRef.current?.focus();
else birthRef.current?.focus();
return;
}
// 숫자 0000.00.00 형식으로 변환
const formattedBirth = `${birthRegex.slice(0, 4)}.${birthRegex.slice(4, 6)}.${birthRegex.slice(6, 8)}`;
const newUser: User = {
id: users.length ? users[users.length - 1].id + 1 : 1,
name: newName,
birth: formattedBirth,
};
setUsers([...users, newUser]);
setNewName(""); // 입력창 초기화
setNewBirth("");
}
// update 함수
const updateUser = (id: number) => {
// 이름 수정
const updatedName = prompt("수정할 이름 입력, 취소시 기존 값 유지");
let formattedBirth: string | null = null;
let birthOnlyDigits: string | null = null;
// 생일 수정 및 검증
while (true) {
const updatedBirth = prompt("수정할 생일 입력 (숫자 8자리), 취소시 기존 값 유지");
if (!updatedBirth) break; // 취소 누르면 종료
// 숫자만 추출
birthOnlyDigits = updatedBirth.replace(/\D/g, "");
if (birthOnlyDigits.length === 8) {
formattedBirth = `${birthOnlyDigits.slice(0, 4)}.${birthOnlyDigits.slice(4, 6)}.${birthOnlyDigits.slice(6, 8)}`;
break; // 올바르면 변환하고 루프 종료
} else {
alert("생일은 숫자 8자리로 입력해주세요. ex) 19880101");
// while 계속 → prompt 다시 뜸
}
}
setUsers(prev =>
prev.map(user => (user.id === id
? { ...user,
name: updatedName?.trim() || user.name, // 옵셔널이 없으면 빨간줄 나는 이유 => prompt가 string|null을 반환하기 때문에 null일 경우 타입이 안맞아서 빨간줄이 뜸
birth: formattedBirth?.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="inpName">이름</label>
<input
type="text"
id="inpName"
placeholder="이름을 입력하세요"
ref={nameRef}
value={newName}
onChange={e => setNewName(e.target.value)}
onKeyDown={e => {
if(e.key === "Enter") birthRef.current?.focus();
}}
/>
<br />
<label htmlFor="inpBirth">생일</label>
<input
type="text"
id="inpBirth"
placeholder="ex) 2000.01.01"
ref={birthRef}
value={newBirth}
onChange={e => setNewBirth(e.target.value)}
onKeyDown={e => {
if(e.key === "Enter") addUser(); // 엔터시 추가 함수 호출
}}
/>
<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>
)
}
'개발 > 🔵 React-TypeScript' 카테고리의 다른 글
| 팝업 컴포넌트 1차 (0) | 2025.09.18 |
|---|---|
| 버튼 컴포넌트 1차 (0) | 2025.09.18 |
| Enter시 초점 이동, 함수 실행 (0) | 2025.09.17 |
| 전체선택 구현하기 (0) | 2025.09.16 |
| 타입스크립트 문법 해석 (1) | 2025.08.27 |
