노마드코더 인스타그램 클론코딩 바로가기 https://nomadcoders.co/instaclone
styled-components를 이용해 구현
코드 구현
Login.js에서 styled-components를 이용해 한 파일에서 다 구현을 마친 다음 공통적으로 사용해야하는 컴포넌트를 하나하나씩 생성하면서 코드를 정리한다.
const FaceBookLogin = styled.div`
margin-bottom: 20px;
color: #385285;
span {
font-weight: 600;
margin-left: 10px;
}
`;
const Login = () => {
const [username, setUsername] = useState("");
const [usernameError, setUsernameError] = useState("");
const onUsernameChange = (e) => {
setUsernameError("");
setUsername(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(username);
if (username === "") {
setUsernameError("Not empty pls.");
}
if (username.length < 10) {
setUsernameError("too short");
}
};
return (
<AuthLayout>
<FormBox>
<FontAwesomeIcon icon={faInstagram} size="3x" />
<form onSubmit={handleSubmit}>
{usernameError}
<Input
onChange={onUsernameChange}
value={username}
type="text"
placeholder="사용자 이름"
/>
<Input type="password" placeholder="비밀번호" />
<Button
disabled={username === "" || username.length < 10}
type="submit"
value="로그인"
/>
</form>
<Separator />
<FaceBookLogin>
<FontAwesomeIcon icon={faFacebookSquare} />
<span>Facebook으로 로그인</span>
</FaceBookLogin>
<span>비밀번호를 잊으셨나요?</span>
</FormBox>
<BottomBox
cta="계정이 없으신가요 ?"
link={routes.signUp}
linkText="가입하기"
/>
</AuthLayout>
);
};
export default Login;
npm i react-helmet-async
: Page Title을 지정하는 라이브러리
해당 페이지에서 Helmet을 이용해 적용하고 싶은 PageTitle을 적어준다.
단 ! 모든 Helmet Component은 HelmetProvider안에 존재해야 하기 때문에 프로젝트를 HelmetProvider로 감싸준다.
// App.js
import {HelmetProvider} from "react-helmet-async";
return (
<HelmetProvider}
...
</HelmetProvider}
)
// PageTitle.js
import {Helmet} from "react-helmet-async";
import {PropTypes} from "prop-types";
const PageTitle = ({title})=>{
return (
<Helmet>
<title>{title} | Instagram</title>
</Helmet>
)
}
PageTitle.propTypes = {
title:PropTypes.string.isRequired,
}
export default PageTitle;
// Login.js
return (
<AuthLayout>
<PageTitle title="LogIn"/>
</AuthLayout>
)
yarn add react-hook-form@6.15.1
React Hook Form 문서 =====> https://react-hook-form.com/kr/
// useForm 기본 옵션 const {register} = useForm({ mode: 'onSubmit', reValidateMode: 'onChange', defaultValues: {}, resolver: undefined, context: undefined, criteriaMode: "firstError", shouldFocusError: true, shouldUnregister: true, })
npm install @hookform/resolvers
<form>
<input ref={register} name="username" type="text" placeholder="사용자이름"/>
<input ref={register} name="password" type="password" placeholder="패스워드"/>
</form>
register의 기본적인 사용법은 위 코드와 같다.
ref로 register를 연결해주고 중요한 것은 name값을 지정해줘야 한다.
다음과 같이 input에 치는 값이 지정해준 name에 들어가게 된다.
이전의 방법에서 다음과 같은 기능을 구현할려면 state생성해주고 onChange로 변경될때마다 setState해줘야 했는데 React Hook Form을 사용해주면 간단하게 구현 가능
handleSubmit은 onSubmit을 호출하기 전의 입력값을 확인한다.
또한 handleSubmit을 이용해 valid와 invalid data에 대해서 제어 가능하다.
validate를 이용해서 custom validate를 구현 가능 하다.
const onSubmitValid = (data)=>console.log(data)
const onSubmitInvalid = (data)=>console.log(data)
return (
<form onSubmit={handleSubmit(onSubmitValid,onSubmitInvalid)}
<input ref={register({
required:"Username is required",
minLength: 5,
validate: (currentValue)=>currentValue.includes("potato");
})}/>
</form>
)
현재 Validate : required & 길이 5 이상 (valid) & username에 potato 포함
validate는 true를 return하면 valid false를 return하면 invalide
input에 설정한 name에 값이 들어가 있는 것을 볼 수 있다.
type은 이제 invalid된 rule을 나타낸다.
formState.isValid는 현재 모드에 따른 유효성검사의 결과(Boolean)값을 리턴한다.
formState를 사용해서 쉽게 버튼의 활성화를 컨트롤 할 수 있다.
Button에 props로 disabled를 전달해주는데 값은 !formState.isValid를 전달한다.
<Button type="submit" value="로그인" disabled={!formState.isValid}
styled-components를 사용하기 때문에 css에서 props로 값을 전달 받을 수 있다.
opacity: ${(props) => (props.disabled ? "0.5" : "1")};
errors는 각 input의 유효성검사가 Invalid인 경우의 inputName과 message를 return 한다.
errors.inputName.message를 이용해 화면에 띄울 수 있다.