✅ 마크업 및 스타일링
✅ 로그인, 회원가입 페이지 기능 구현
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
을 처음 사용해봐서 모르기도 했지만, 내가 잘 찾아서 했다면 번거롭지 않았을 텐데 하는 생각에 아쉬움이 들었다. 다음에는 설명글을 자세하게 읽고 시작해야겠다.