import { useRef, useState } from "react";
const errorStyle = {
fontSize: "12px",
color: "red",
fontWeight: "bold",
};
const emailExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const cellphoneExp = /^(01[016789]{1})[0-9]{3,4}[0-9]{4}$/;
function App() {
// ❌이런 식으로 상태 하나하나씩 useState()를 사용해서 하지 않을 것!(코드 너무 길어진다)❌
// const [name, setName] = useState("");
// const [email, setEmail] = useState("");
// const [cellphone, setCellphone] = useState("010");
// const handleNameChange = (event) => {
// setName(event.target.value);
// };
// const handleEmailChange = (event) => {
// setEmail(event.target.value);
// };
// const handleCellphoneChange = (event) => {
// setCellphone(event.target.value);
// };
// 유저의 상태 관리하는 State 시스템
const [user, setUser] = useState({
name: "",
email: "",
cellphone: "010",
});
const [errors, setErrors] = useState({});
// 🟢 DOM 객체에 직접 접근하려 할 때..
// name 인풋 요소를 가상 돔으로 가져오기 위해 사용되는 useRef
// Null: 초기값(useRef가 처음 렌더링될 때 반환, current속성에 설정됨)을 null으로 지정
// ... 처음 렌더링될 때만 사용되며 이후 업데이트해도 렌더링에는 영향을 미치지 않습니다.
// React는 컴포넌트가 ✨렌더링된 후에야 해당 DOM 요소를 참조✨할 수 있으므로, 초기값으로 null을 설정해 두는 것이 일반적입니다.
const nameElem = useRef(null);
const emailElem = useRef(null);
const cellphoneElem = useRef(null);
// 하나의 이벤트 핸들러로 처리!
const handleChange = (event) => {
const newUser = { ...user, [event.target.name]: event.target.value };
setUser(newUser);
};
// 💥 여기서 대괄호는 event.target.name의 값을 계산된 속성명(computed property name)으로 사용하기 위해서이다. JavaScript 객체 리터럴에서 대괄호를 사용하면, 객체의 속성 이름을 동적으로 설정할 수 있습니다. 이는 객체의 키(key)가 변수나 표현식으로 지정되어야 할 때 유용..
// 만약 대괄호 없이 event.target.name이라고 쓰면 우리가 의도한 변수로 인식되지 않고, 이 문자열 자체가 속성 이름으로 해석되어 'event.target.name'이라는 이름의 Key에 대한 value가 event.target.value로 설정되기 때문에, 다양한 입력 필드의 상태를 하나의 user 객체에서 관리할 수 있도록 동적으로 속성명이 바뀌게 할 수 없는 문제점이 생긴다.
// 🔸 form 태그의 action이라는 Url로 요청을 보내는 automatic behavior 발생
// 나중에는 브라우저 기본동작인 form요소의 submit 이벤트 호출을 이용하는 게 아닌, ajax 비동기통신 사용할 예정..
const handleSubmit = (event) => {
// 브라우저의 기본 동작 취소 (submit 동작 취소)
event.preventDefault(); // 내가 알아서 ajax 통해서 서버에 요청 보낼테니까 브라우저 너는 그냥 가만히 있어!
// 입력 메시지 검증 작업
let newErrors;
if (user.name.trim() === "") {
newErrors = { name: { message: "이름을 입력하세요." } };
nameElem.current.focus();
} else if (user.name.trim().length < 2) {
newErrors = { name: { message: "이름을 2글자 이상 입력하세요." } };
nameElem.current.focus();
} else if (user.email.trim() === "") {
newErrors = { email: { message: "이메일을 입력하세요." } };
emailElem.current.focus();
} else if (user.cellphone.trim() === "") {
newErrors = { cellphone: { message: "휴대폰 번호를 입력하세요." } };
cellphoneElem.current.focus();
} else if (!emailExp.test(user.email)) {
newErrors = {
email: {
message: "이메일 양식에 맞지 않습니다.",
},
};
emailElem.current.focus();
} else if (!cellphoneExp.test(user.cellphone)) {
newErrors = {
cellphone: {
message: "휴대폰 번호 양식에 맞지 않습니다.",
},
};
cellphoneElem.current.focus();
}
if (newErrors) {
// 검증 실패
setErrors(newErrors);
} else {
// 검증 통과
setErrors({});
console.log("서버에 전송", user);
}
};
return (
<>
<h1>05 회원가입 입력값 상태 관리</h1>
<form onSubmit={handleSubmit}>
<label htmlFor="name">이름</label>
<input
id="name"
name="name"
value={user.name}
onChange={handleChange}
ref={nameElem} // 🟢
/>
<br />
<div style={{ errorStyle }}>{errors.name?.message}</div>
<label htmlFor="email">이메일</label>
<input
id="email"
name="email"
value={user.email}
onChange={handleChange}
ref={emailElem} // 🟢
/>
<br />
<div style={{ errorStyle }}>{errors.email?.message}</div>
<label htmlFor="cellphone">휴대폰</label>
<input
id="cellphone"
name="cellphone"
value={user.cellphone}
onChange={handleChange}
ref={cellphoneElem} // 🟢
/>
<br />
<div style={{ errorStyle }}>{errors.cellphone?.message}</div>
<button type="submit">가입</button>
</form>
<p>
이름: {user.name}
<br />
이메일: {user.email}
<br />
휴대폰: {user.cellphone}
<br />
</p>
</>
);
}
export default App;
'Musta React' 카테고리의 다른 글
[✍🏼 1/4 (Sat)] Prop을 넘겨주는 방식에 따른 useMemo() 사용 여부 - 부모 컴포넌트에서 분해 or 자식 컴포넌트에서 분해 (0) | 2025.01.04 |
---|---|
[✍🏼 1/4 (Sat)] useMemo() 복습 (0) | 2025.01.04 |
11/27 (Wed) 상태관리목적이 "아닌" useSearchParams()의 사용 & Pagination 로직 이해 & Context API (1) | 2024.11.27 |
11/26 (Tue) HTTP 통신과 Ajax & 리액트 라우터가 제공하는 훅 (0) | 2024.11.26 |
11/21 (Thur) ch03-hooks/05-useMemo (0) | 2024.11.22 |