React/NodeBird(ZeroCho)

회원가입 페이지 만들기(커스텀 훅)

느리지만 꾸준하게 2021. 9. 17. 19:03

signup.js에서 AppLayout로 일단 한번 감싸준다.

antd 자체에 Form태그가 있기 때문에 임포트 해준다.

 

알다시피 onFinish는 내부적으로 e.preventDefault가 자동으로 되기 때문에 따로 할 필요가 없다.

signup.js는 아래와 같이 해주고

// signup.js

import React, { useCallback, useState } from 'react';
import Head from 'next/head';
import { Form, Input } from 'antd';

import AppLayout from '../components/AppLayout';


const Signup = () => {
    const [id, setId] = useState('');
    const onChangeId = useCallback((e) => {
        setId(e.target.value);
    }, []);


    const [nickname, setNickname] = useState('');
    const onChangeNickname = useCallback((e) => {
        setNickname(e.target.value);
    }, []);

    const [password, setPassword] = useState('');
    const onChangePassword = useCallback((e) => {
        setPassword(e.target.value);
    }, []);


    const onSubmit = useCallback(() => {

    }, []);

    return (
        <AppLayout>
            <Head>
                <title>회원가입 | NodeBird</title>
            </Head>
            <Form onFinish={onSubmit}>
                <div>
                    <label htmlFor="user-id">아이디</label>
                    <br />
                    <Input name="user-id" value={id} required onChange={onChangeId}/>
                </div>
                <div>
                    <label htmlFor="user-id">닉네임</label>
                    <br />
                    <Input name="user-id" value={nickname} required onChange={onChangeNickname}/>
                </div>
                <div>
                    <label htmlFor="user-id">비밀번호</label>
                    <br />
                    <Input name="user-password" type="password" value="{password}" required onChange={onChangePassword}/>
                </div>
                <div>
                    <label htmlFor="user-id">비밀번호체크</label>
                    <br />
                    <Input
                        name="user-password-check"
                        type="password"
                        value={passwordCheck}
                        required
                        onChange={onChangePasswordCheck} 
                    />
                </div>
            </Form>
        </AppLayout>
    );
};

export default Signup;

 

LoginForm에서도 보면 비슷하게 형태가 나와있다. state 하나 만들고 그거 바꾸는 callback만들고 하는 형태이다.

이러한 세트형태가 form에는 자주 보일것이다.

// LoginForm.js

const LoginForm = ({ setIsLoggedIn }) => {
  const [id, setId] = useState('');
  const onChangeId = useCallback((e) => {
    setId(e.target.value);
  }, []);

  const [password, setPassword] = useState('');

  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
  }, [])

  const style = useMemo(() => ({ marginTop: 10}), []);

  const onSubmitForm = useCallback(() => {
    console.log(id, password);
    setIsLoggedIn(true);
  }, [id, password]);

const LoginForm 부분을 커스텀으로 만들어보자. 훅을 쓸 수 있는 조건이 있는데 반복문이나 조건문 함수안에서는 안되고 컴포넌트 안에서만 되는데 유일한 예외가 커스텀 훅이다.

// LoginForm.js
const LoginForm = ({ setIsLoggedIn }) => {

// 이 부분부터
  const [id, setId] = useState('');
  const onChangeId = useCallback((e) => {
    setId(e.target.value);
  }, []);

  const [password, setPassword] = useState('');

  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
  }, [])

  const style = useMemo(() => ({ marginTop: 10}), []);

  const onSubmitForm = useCallback(() => {
    console.log(id, password);
    setIsLoggedIn(true);
  }, [id, password]);

hooks 폴더를 만들고 useInput.js 파일을 만들어서 작업을 하자. 평소에 중복을 제거하는 거 처럼 똑같이 만들어준다.

value setValue 리턴을 해주는데 useState와 useCallback을 합친거니까 return 부분에 value는 value, setValue 대신에 handler를 넣어준다. 이렇게 커스텀 훅으로 리턴해주면 둘이 합쳐져서 리턴이 된다.

// useInput.js

import { useState, useCallback } from 'react';

export default (initValue = null) => {
    const [value, setValue] = useState(initValue);
    const handler = useCallback((e) => {
        setValue(e.target.value);
    }, []);
    return [value, handler];
}

 

다시 로그인 폼으로 가서 아래와 같이 줄일 수 있다. hooks들도 중복되면 중복을 제거할 수 있는 것이다.

// LoginForm.js

const LoginForm = ({ setIsLoggedIn }) => {
  const [id, onChangeId] = useInput('');
  const [password, onChangePassword] = useInput('');

  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
  }, [])

  const onSubmitForm = useCallback(() => {
    console.log(id, password);
    setIsLoggedIn(true);
  }, [id, password]);

 

signup파일에 와서 아래와 같이 바꿔준다. 여기서는 중복체크도 해줘야 하기 때문에 이 부분에서 차이가 난다.

// signup.js

const Signup = () => {
    const [id, onChangeId] = useInput('');
    const [nickname, onChangeNickname] = useInput('');
    const [password, onChangePassword] = useInput('');

    const onSubmit = useCallback(() => {

    }, []);

 

이 부분을 useInput 커스텀 훅으로 줄일수도 있지만 하나 더 들어간다.

 const [passwordCheck, setPasswordCheck] = useState('');
    const onChangePasswordCheck = useCallback((e) => {
        setPasswordCheck(e.target.value);
    }, []);

패스워드 체크와 패스워드가 다른지를 확인하는 것이다. 이 부분이 달라서 얘는 커스텀 훅으로 합쳐주지를 못했다.

// signup.js

    const onChangePasswordCheck = useCallback((e) => {
        setPasswordCheck(e.target.value);
        setPasswordError(e.target.value !== password);
    }, [password]);

 

비밀번호랑 비밀번호 확인이 일치하는지 비밀번호 확인이 일치하지 않으면 passwordError 부분이 true가 될 것이다.

true가 되면 에러를 표시해주자.

// signup.js
const [id, onChangeId] = useInput('');
    const [nickname, onChangeNickname] = useInput('');
    const [password, onChangePassword] = useInput('');
    const [passwordCheck, setPasswordCheck] = useState('');
    const [passwordError, setPasswordError] = useState(false);
    const onChangePasswordCheck = useCallback((e) => {
        setPasswordCheck(e.target.value);
        setPasswordError(e.target.value !== password);
    }, [password]);

 

비밀번호 에러가 있으면 아래 문구가 나오게 하고 약관동의 체크박스가 나오게 한다.

// signup.js

import { Form, Input, Checkbox } from 'antd';
import styled from 'styled-components';
import AppLayout from '../components/AppLayout';
import useInput from '../hooks/useInput';


const ErrorMessage = styled.div`
    color: red;
`



                {passwordError && <Errormessage>비밀번호가 일치하지 않습니다.</Errormessage>}
                <div>
                    <Checkbox name="user-term" checked={term} onChange={onChangeTerm}>제로초 말을 잘 들을 것을 동의합니다.</Checkbox>
                    {termError && <div style={{ color: 'red' }}>약관에 동의하셔야 합니다.</div>}
                </div>
            </Form>
        </AppLayout>
    );
};

 

  

// signup.js

const Signup = () => {
    const [id, onChangeId] = useInput('');
    const [nickname, onChangeNickname] = useInput('');
    const [password, onChangePassword] = useInput('');
    
    const [passwordCheck, setPasswordCheck] = useState('');
    const [passwordError, setPasswordError] = useState(false);
    const onChangePasswordCheck = useCallback((e) => {
        setPasswordCheck(e.target.value);
        setPasswordError(e.target.value !== password);
    }, [password]);
    
    const [term, setTerm] = useState('');
    const [termError, setTermError] = useState(false);
    const onChangeTerm = useCallback((e) => {
        setTerm(e.target.checked);
        setTermError(false);
    }, []);

    const onSubmit = useCallback(() => {

    })

 

termError는 false인데 언제 true가 되냐 제출할때 true가 되게 제출버튼을 만든다.

                {passwordError && <Errormessage>비밀번호가 일치하지 않습니다.</Errormessage>}
                <div>
                    <Checkbox name="user-term" checked={term} onChange={onChangeTerm}>제로초 말을 잘 들을 것을 동의합니다.</Checkbox>
                    {termError && <ErrorMessage style={{ color: 'red' }}>약관에 동의하셔야 합니다.</ErrorMessage>}
                </div>
            </Form>
        </AppLayout>
    );
};

 

 

약관동의를 누르지 않았으면 에러가 뜨게 만든다. 그리고 사용자의 인풋 받는거를 여러번 체크를 하자.

    const onSubmit = useCallback(() => {
        if (password !== passwordCheck) {
            return setPasswordError(true);
        }
        if (!term) {
            return setTermError(true);
        }
        console.log(id, nickname, password)
    }, [password, passwordCheck, term]);
const Signup = () => {
    const [id, onChangeId] = useInput('');
    const [nickname, onChangeNickname] = useInput('');
    const [password, onChangePassword] = useInput('');
    
    const [passwordCheck, setPasswordCheck] = useState('');
    const [passwordError, setPasswordError] = useState(false);
    const onChangePasswordCheck = useCallback((e) => {
        setPasswordCheck(e.target.value);
        setPasswordError(e.target.value !== password);
    }, [password]);
    
    const [term, setTerm] = useState('');
    const [termError, setTermError] = useState(false);
    const onChangeTerm = useCallback((e) => {
        setTerm(e.target.checked);
        setTermError(false);
    }, []);

    const onSubmit = useCallback(() => {
        if (password !== passwordCheck) {
            return setPasswordError(true);
        }
        if (!term) {
            return setTermError(true);
        }
        console.log(id, nickname, password)
    }, [password, passwordCheck, term]);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 조현영: [리뉴얼] React로 NodeBird SNS 만들기>

https://www.inflearn.com/course/%EB%85%B8%EB%93%9C%EB%B2%84%EB%93%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A6%AC%EB%89%B4%EC%96%BC/dashboard

 

[리뉴얼] React로 NodeBird SNS 만들기 - 인프런 | 강의

리액트 & 넥스트 & 리덕스 & 리덕스사가 & 익스프레스 스택으로 트위터와 유사한 SNS 서비스를 만들어봅니다. 끝으로 검색엔진 최적화 후 AWS에 배포합니다., 새로 만나는 제로초의 리액트 노드버

www.inflearn.com

 

'React > NodeBird(ZeroCho)' 카테고리의 다른 글

리덕스의 원리와 불변성  (0) 2021.10.26
redux설치  (0) 2021.10.26
프로필 페이지 만들기  (0) 2021.09.17
noreferrer&noopener  (0) 2021.09.17
더미 데이터로 로그인  (0) 2021.09.17