멘토님 앞에서 우리가 그간 어떻게 미팅을 진행해왔는지 보여주고 그에 대한 피드백을 가지는 시간을 가졌다.
로그인 레이아웃과 기능구현을 일단 대강 맞추고 나는 회원가입페이지를 만들기 시작했다.
회원가입페이지는 여러개의 입력칸이 존재한다.
다음은 배민문방구의 회원가입란이다.
우리 팀은 여기서 아이디
, 비밀번호
, 닉네임(이름)
, 이메일
, 휴대폰번호
를 회원가입에 필요한 정보로 받기로 했다.
백엔드도 이 데이터 요건에 맞추어 API 기능정의서를 작성하였다.
하나의 input을 Component화하여 재사용하는게 좋을 것 같았다.
3개의 Component가 완성되었다.
SignUpInput
SignUpInputList
SignUp
import React from 'react';
import './SignUpInput.scss';
function SignUpInput({
type,
signupInfo,
value,
text,
placeholder,
setSignupInfo,
name,
}) {
const onChange = e => {
setSignupInfo({
...signupInfo,
[e.target.name]: e.target.value,
});
};
return (
<div className="SignUpInput">
<div className="inputTextBox">
<p className="inputText">{`* ${text}`}</p>
</div>
<div className="inputWrapper">
<input
className="signUpInput"
name={name}
onChange={onChange}
type={type}
placeholder={placeholder}
value={value}
/>
</div>
</div>
);
}
export default SignUpInput;
import React from 'react';
import './SignUpInput.scss';
function SignUpInput({
type,
signupInfo,
value,
text,
placeholder,
setSignupInfo,
name,
}) {
const onChange = e => {
setSignupInfo({
...signupInfo,
[e.target.name]: e.target.value,
});
};
return (
<div className="SignUpInput">
<div className="inputTextBox">
<p className="inputText">{`* ${text}`}</p>
</div>
<div className="inputWrapper">
<input
className="signUpInput"
name={name}
onChange={onChange}
type={type}
placeholder={placeholder}
value={value}
/>
</div>
</div>
);
}
export default SignUpInput;
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import SignUpInputList from './SignUpInputList';
import './SignUp.scss';
function SignUp() {
const [signUpInfo, setSignUpInfo] = useState({
signUpId: '',
signUpPw: '',
signUpPwCheck: '',
signUpEmail: '',
signUpNick: '',
signUpPhone: '',
});
const {
signUpId,
signUpPw,
signUpPwCheck,
signUpEmail,
signUpNick,
signUpPhone,
} = signUpInfo;
const navigate = useNavigate();
const goToLogin = () => {
navigate('/login');
};
const isValidPw = value => {
let pwRegex =
/^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+]).{8,16}$/;
return pwRegex.test(value);
};
const isPwSame = signUpPw !== signUpPwCheck;
const isValidEmail = value => {
let emailRegex =
/([\w-.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
return emailRegex.test(value);
};
const isValidPhone = value => {
let phoneRegex = /^[0-9\b -]{0,13}$/;
return phoneRegex.test(value);
};
const isFilledMandatory =
!signUpId ||
!signUpPw ||
!signUpPwCheck ||
!signUpEmail ||
!signUpNick ||
!signUpPhone;
const signUpValidation = e => {
e.preventDefault();
if (isFilledMandatory) {
alert('필수항목을 입력해주세요!');
} else if (!isValidPw(signUpPw)) {
alert(
'사용불가! 영문자,숫자,특수문자 조합으로 8-16글자 범위로 입력해주세요! '
);
} else if (isPwSame) {
alert('비밀번호와 비밀번호확인은 같아야 합니다.');
} else if (!isValidEmail(signUpEmail)) {
alert('올바른 이메일 형식이 아닙니다.');
} else if (!isValidPhone(signUpPhone)) {
alert('올바른 전화번호 형식이 아닙니다.');
}
};
const signUpRegister = () => {
fetch('http://10.58.5.43/users/signup', {
method: 'POST',
body: JSON.stringify({
account: signUpId,
password: signUpPw,
email: signUpEmail,
phone: signUpPhone,
nickname: signUpNick,
}),
})
.then(res => res.json())
.then(res => {
if (res.message === 'ACCOUNT ALREADY EXISTS') {
alert('중복된 아이디입니다!');
} else if (res.message === 'NICKNAME ALREADY EXISTS') {
alert('중복된 닉네임입니다!');
} else if (res.message === 'E-MAIL ALREADY EXISTS') {
alert('중복된 이메일입니다!');
} else if (res.message === 'PHONE-NUMBER ALREADY EXISTS') {
alert('중복된 휴대폰번호입니다!');
}
});
};
return (
<div className="signUp">
<form className="signUpForm" onSubmit={signUpValidation}>
<header className="signUpHeader">
<h1 className="info">기본정보</h1>
<h4 className="sideInfo">
*표시는 반드시 입력하셔야 하는 항목입니다.
</h4>
</header>
<SignUpInputList
setSignupInfo={setSignUpInfo}
signupInfo={signUpInfo}
/>
<div className="signUpButtonWrapper">
<button className="signUpCancelBtn" onClick={goToLogin}>
취소
</button>
<button className="signUpBtn" onClick={signUpRegister}>
회원가입
</button>
</div>
</form>
</div>
);
}
export default SignUp;
몬스터과제를 하면서 너무 monster 양식의 컴포넌트화에 익숙해져 그대로 프로젝트에 도입하려던게 문제점을 제공했다.
몬스터과제 역시 컴포넌트를 가장 기본 컴포넌트, 기본 컴포넌트를 나열하는 리스트 컴포넌트, 그리고 그것을 화면에 렌더링해줄 컴포넌트로 구성하였는데 뭔가 이 방법을 직접 프로젝트와 같은 실습에도 적용을 해봐야 할것 같다는 생각에 회원가입페이지를 같은 방식으로 진행하였다.
그러다보니까 state관리가 매우 힘들어졌다. ㅠㅠ
사실 그냥 html로 input을 다 작성해줄 수 있다. 6개밖에 안되기 때문에 그러면 state관리가 쉽겠지만 후에 유지보수를 한다 했을 때
const data와 component를 사용한 코드가 더 좋은 측면이 많기 때문에 내가 쓴 코드를 유지하기로 결심하였다.(멘토님의 의견도 반영)
결국 props를 여러개 만들고 state이름을 상수데이터에 inputName으로 넣는 식으로 어떻게든 해결하였다.(멘토님과 동기의 도움을 많이 받았다.)
나중에 다른 동기분의 코드를 보니까 컴포넌트를 2개만 활용해서(List컴포넌트 제외)나와 같은 방법으로 간결하게 한 것을 보고 추후 리팩토링할 때 다시한번 해볼 생각이다.
회원가입에 대한 유효성 검사는 조건을 만족하지 않았을 때 input 밑에 경고문이 생겨나는 식으로 기능 구현을 하고 싶었는데 생각보다 잘 안되었다.
회의 결과 세세한 기능구현에 포커싱을 하기보다는 전체적으로 모든 페이지를 1차적으로 완성하고 우리 팀의 첫번째 목표였던
루프(회원가입 => 로그인 => 메인페이지 => 상세페이지 => 장바구니 => 결제 => 마이페이지에서 확인)
를 구현하는데 집중하자는 팀원들의 의견을 반영하여 일단 유효성 검사에 대한 경고문을 alert창을 뜨게하는 것으로 대체하였다.
추후 시간이 남으면 다시 구현해 볼 생각이다.