✅ 마크업 및 스타일링
✅ 로그인, 회원가입 페이지 기능 구현
Input-Text <Input
name="email"
value={formData.email}
onChange={handleSignUpChange}
placeholder="이메일을 입력하세요"
icon={<Mail />}
error={errors.email}
errorMessage={getEmailStatusMessage(emailDuplicateStatus)}
successMessage={emailDuplicateChecked && "사용 가능한 이메일 입니다"}
width="75%"
/>
Input-Radio <Radio
name="authority"
value={formData.authority}
onChange={handleSetAuthority}
data={[
{ value: AUTH_LEVEL.teacher, label: "선생님" },
{ value: AUTH_LEVEL.parent, label: "부모님" },
]}
error={errors.authority}
errorMessage="원하시는 계정 유형을 선택해 주세요."
/>
Portals : 모달을 띄우는 새로운 방식(처음 사용해봤다)public/index.html에 modalDom Element를 만들었다. <body>
<div id="root"></div>
<div id="modalDom"></div>
</body>
const elRef = document.getElementById("modalDom");
return ReactDOM.createPortal(
<Wrapper ref={ref} onClick={handleClick}>
{children}
</Wrapper>,
elRef
);
bcryptjs :패스워드 암호화LocalStorage에 사용자 정보를 저장하여 사용하기 때문에 별도로 token을 발행하거나 하진 않지만, 비밀번호는 암호화해서 저장하기로 했다.
bcryptjs를 설치하고 아래의 함수를 사용해주었다.
hashSync의 두번째 매개변수는 salt 값이다. 숫자가 클수록 암호화가 잘되지만 성능이 떨어질 수 있다는 단점이 있다.
export const hashSync = (pw) => bcrypt.hashSync(pw, 8);
export const compareSync = (pw, hash) => bcrypt.compareSync(pw, hash);
react-daum-postcode : 주소 API 라이브러리를 다운받아서 진행forwardRef : 신용카드 4글자 입력 후 포커스 자동으로 옆으로 이동되게 하기inputRef 의 초기값을 배열로 생성해서 Input의 ref에 연결해줬다. const inputRef = useRef([]);
//생략...
<div className="card-wrapper">
{Array.from({ length: 4 }, (_, i) => i).map((idx) => (
<div key={idx}>
<Input
ref={(r) => (inputRef.current[idx] = r)} // ✅ 이 부분!
name={`num${idx}`}
value={creditCardNumber[`num${idx}`]}
onChange={handleChangeCreditCardNumber}
maxLength={4}
numberOnly
/>
<span>-</span>
</div>
))}
</div>

import React, { forwardRef } from "react";
//생략...
export default forwardRef(Input);
- 요소별 정규식 패턴을 만든다.
export const isEmail = (checkString) => {
const emailRegex =
/^(([^<>()\[\].,;:\s@"]+(\.[^<>()\[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
return emailRegex.test(checkString);
};
export const isPassword = (checkString) => {
const passwordRegex = /(?=.*\d{1,50})(?=.*[~`!@#$%\^&*()-+=]{1,50})(?=.*[a-zA-Z]{1,50}).{8,50}$/;
return passwordRegex.test(checkString);
};
//이후 다른 정규식은 생략...
validator 함수에 유효성 검사 판별식 넣어준다
반복문을 수행하면서 각 항목마다 value값이 유효성 검사에 맞는지 확인하고,
에러일 경우 setErrors 함수를 통해 에러나는 부분을 true로 저장한다
const validator = {
authority: (authority) => !(authority === AUTH_LEVEL.unknown),
email: (email) => isEmail(email),
pw: (pw) => isPassword(pw),
pwCheck: (pwCheck) => pwCheck === formData.pw,
name: (name) => isName(name),
address: (address) => !(address === ""),
detailAddress: (detailAddress) => !(detailAddress === ""),
dateOfBirth: (dateOfBirth) => isDateOfBirth(dateOfBirth),
creditCardNum: (creditCardNum) => isCreditNum(creditCardNum),
};
const isAllValid = (data) => {
for (const name in data) {
const value = data[name];
const validateFunction = validator[name];
if (!validateFunction(value)) {
setErrors((prev) => ({
...prev,
[name]: true,
}));
return false;
} else {
setErrors((prev) => ({
...prev,
[name]: false,
}));
}
}
return true;
};
- 로그인/회원가입 버튼을 눌렀을 경우(
Submit) 유효성 검사를 진행한다.
const handleSignupSubmit = (e) => {
e.preventDefault();
const allValid = isAllValid(formData);
if (allValid) { // ✅ 유효성 검사 통과!
// ...
}
};
유효성 검사를 하면서, 하나의 Func에서 setter 함수를 여러번 호출했는데 업데이트가 반영되지 않고 마지막 setter 함수만 실행되는 결과를 얻었다.
왜 그렇지...왜 이렇게 나오지..계속 생각했는데 setter가 비동기 함수라는걸 잊고 있었다🤦♀️
잊지말자. 리액트에서 setState는 비동기로 작동하므로 상태를 업데이트할 경우, 업데이트 된 상태는 즉시 반영되지 않는다!!
public/index.html에 엘리먼트를 생성하시고 작업했는데, 내가 수정하면서 이걸 컴포넌트 안으로 가져왔다. 근데 다른 팀원분들과 머지를 다 하고보니 public/index.html에 있는게 맞는거 였다.Portal을 처음 사용해봐서 모르기도 했지만, 내가 잘 찾아서 했다면 번거롭지 않았을 텐데 하는 생각에 아쉬움이 들었다. 다음에는 설명글을 자세하게 읽고 시작해야겠다.