TIL 09 - 인스타그램 클론코딩 (9) Login / SignUp

MOON·2021년 5월 11일
0
post-thumbnail

노마드코더 인스타그램 클론코딩 바로가기 https://nomadcoders.co/instaclone

👀 LogIn UI

styled-components를 이용해 구현

👀 SignUp UI

코드 구현
Login.js에서 styled-components를 이용해 한 파일에서 다 구현을 마친 다음 공통적으로 사용해야하는 컴포넌트를 하나하나씩 생성하면서 코드를 정리한다.

🙀 Login.js의 코드 정리를 마친 코드

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;

🙀 Auth(Login,SignUp)의 공통 컴포넌트

🙀 Helmet Component

Install

npm i react-helmet-async : Page Title을 지정하는 라이브러리

사용방법

해당 페이지에서 Helmet을 이용해 적용하고 싶은 PageTitle을 적어준다.
단 ! 모든 Helmet Component은 HelmetProvider안에 존재해야 하기 때문에 프로젝트를 HelmetProvider로 감싸준다.

Page마다 Helmet이 사용되기 때문에 컴포넌트로 구현해주자

// 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>
)

🙀 React Hook Form

  • useForm hook , register이 input 을 위한 state와 onChange와 같은 모든 것들을 해줌
  • yarn add react-hook-form@6.15.1
  • 버전을 지정해준 이유는 최신 버전인 7.0.0 이상의 버전으로 설치했을때는 ref={}에서 에러가 발생한다. 따라서 6.15.1 버전을 설치해주거나 만약 7.0.0이상의 버전으로 설치했을때는 최근 문서를 보면서 바뀐 방법으로 구현해줘야 한다.

React Hook Form 문서 =====> https://react-hook-form.com/kr/

✅ 6.15.1 Version

useForm ?

useForm 옵션

// useForm 기본 옵션
const {register} = useForm({
  mode: 'onSubmit',
  reValidateMode: 'onChange',
  defaultValues: {},
  resolver: undefined,
  context: undefined,
  criteriaMode: "firstError",
  shouldFocusError: true,
  shouldUnregister: true,
})

useForm의 옵션

  1. mode
  2. reValidateMode
  3. defaultValues
  4. resolver

1. mode

  • onSubmit(Default) : (string) 유효성 검사가 submit 이벤트 발생시 이루어진다.
  • onBlur : (string) blur 이벤트는 input을 벗어났을때를 의미하며 이때 유효성 검사가 이루어진다.
  • onChange : (string) 각 input의 change 이벤트가 일어날때마다 유효성 검사가 이루어지지만 랜더링 성능을 떨어뜨리므로 추천하지 않는다.
  • onTouched : (string) 입력이 터치 될 때까지 유효성 검사가 이루어짐
  • all : (string) blur 및 change 이벤트에서 유효성 검사가 이루어짐 . onChange모드가 포함되어져 있기때문에 당연히 랜더링 성능을 떨어뜨리므로 추천 X

2. reValidateMode : onChange | onBlur | onSubmit

  • 재유효성 검사를 언제 할지 설정하는 옵션
  • 기본값은 onChange

3. defaultValues : Record<string, any> = {}

  • defaultValues는 커스텀 훅 안에서 캐싱되므로, defaultValues 값을 초기화하고 싶다면 reset API를 사용하자.
  • defaultValues에서 정의된 값은 watch의 defaultValue 값으로 들어간다.
  • input의 name과 값을 매칭해주면 default로 값이 들어간다.
  • 시도해보지는 않았지만 내생각에 아이디 저장을 체크하고 로그인 했을 때 그 input값을 defaultValues로 매칭해주면 아이디가 저장 될 것같다. 시도해보고 된다면 코드를 올리겠다.

4. resolver : (values: any, context?: object)=>Promise | ResolverResult

npm install @hookform/resolvers

  • 이 함수는 Yup, Joi, Superstruct 등의 외부 유효성 검사 방법들을 실행할 수 있는 함수이다.
  • 반드시 values와 errors 객체를 모두 포함해 리턴해야함 .
  • 반드시 객체들의 기본값은 빈 객체 {}가 되어야 함
  • 사용방법은 공식문서를 참고

const {? ? ? ?} = useForm()

1. register

  • state와 onChange와 같은 방법이 register에 다 담겨 있기 때문에 register만 연결해주면 된다.
<form>
   <input ref={register} name="username" type="text" placeholder="사용자이름"/>
   <input ref={register} name="password" type="password" placeholder="패스워드"/>
</form>

register의 기본적인 사용법은 위 코드와 같다.
ref로 register를 연결해주고 중요한 것은 name값을 지정해줘야 한다.

2. watch

  • console.log(watch()); 의 결과 창은 아래와 같다.

다음과 같이 input에 치는 값이 지정해준 name에 들어가게 된다.
이전의 방법에서 다음과 같은 기능을 구현할려면 state생성해주고 onChange로 변경될때마다 setState해줘야 했는데 React Hook Form을 사용해주면 간단하게 구현 가능

3. handleSubmit

handleSubmit은 onSubmit을 호출하기 전의 입력값을 확인한다.
또한 handleSubmit을 이용해 valid와 invalid data에 대해서 제어 가능하다.

4. Validate

validate를 이용해서 custom validate를 구현 가능 하다.

handleSubmit과 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

valid인 경우 결과창

input에 설정한 name에 값이 들어가 있는 것을 볼 수 있다.

invalid인 경우 결과창

type은 이제 invalid된 rule을 나타낸다.

5. formState

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")};

6. errors

errors는 각 input의 유효성검사가 Invalid인 경우의 inputName과 message를 return 한다.
errors.inputName.message를 이용해 화면에 띄울 수 있다.

0개의 댓글