NEXTJS 로 twitter클론 해보기(5. 더미데이터로 회원가입 페이지 만들기 )

LeeJaeHoon·2021년 12월 9일
0
post-thumbnail

만들기 전 구성

회원가입 페이지를 구성할때 어떤 것들이 필요 할까요?

먼저 form 과 input이 필요하겠죠.

input에는 id, nickname, password, passwordCheck를 만들 것 입니다.

password와 passwordCheck가 다를 경우 오류 메세지를 보이게 할 것입니다.

또한 간단하게 약관동의를 만들 건데요.

유저가 약관동의를 안할경우 또한 오류메세지를 보이게 할 것입니다.

signup.js

import AppLayout from "../components/AppLayout";
import Head from "next/head";
import { Form, Input, Checkbox, Button } from "antd";
import { useCallback, useState } from "react";
import useInput from "../hooks/useInput";
import styled from "styled-components";

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

const Signup = () => {
	//state는 나중에 만들겁니다
	return (
    <>
      <Head>
        <title>회원가입 | NodeBird</title>
      </Head>
      <AppLayout>
        <Form onFinish={onSubmit}>
					{/* id input */}
          <div>
            <label htmlFor="user-id">아이디</label>
            <br />
            <Input name="user-id" value={id} required onChange={onChangeId} />
          </div>
					{/* nickname input */}
          <div>
            <label htmlFor="user-id">닉네임</label>
            <br />
            <Input
              name="user-id"
              value={nickname}
              required
              onChange={onChangeNickname}
            />
          </div>
					{/* password input */}
          <div>
            <label htmlFor="user-id">비밀번호</label>
            <br />
            <Input
              name="user-id"
              type="password"
              value={password}
              required
              onChange={onChangePassword}
            />
          </div>
					{/* passwordCheck input*/}
          <div>
            <label htmlFor="user-id">비밀번호 체크</label>
            <br />
            <Input
              name="user-id"
              type="password"
              value={passwordCheck}
              required
              onChange={onChangePasswordCheck}
            />
            {passwordError && (
              <ErrorMessage>비밀번호가 일치하지 않습니다.</ErrorMessage>
            )}
          </div>
					{/* 약관동의 */}
          <div>
            <Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
               말을 잘 들을 것을 동의합니다.
            </Checkbox>
            {termError && (
              <ErrorMessage>약관에 동의하셔야 합니다.</ErrorMessage>
            )}
          </div>
          <div style={{ marginTop: 10 }}>
            <Button type="primary" htmlType="submit">
              가입하기
            </Button>
          </div>
        </Form>
      </AppLayout>
    </>
  );
};

export default Signup;

Custom Hook

이제 input에 대한 state를 만들 차례인데요. 근데 한가지 문제가 있습니다. input하나하나 마다 value와 onChange이벤트를 달고 그 이벤트에대한 state, eventHandler 코드를 작성한다면 코드양이 너무 많아 질 것입니다. 그래서 공통된 부분은 Custom Hook을 만들어 코드양을 줄이고자 합니다.

hooks폴더를 만들고 useInput.js파일을 만들어 봅시다.

useInput.js

import { useState, useCallback } from "react";

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

이제 위의 useInput을 사용하여 signup.js를 완성해 볼까요?

signup.js

import AppLayout from "../components/AppLayout";
import Head from "next/head";
import { Form, Input, Checkbox, Button } from "antd";
import { useCallback, useState } from "react";
import useInput from "../hooks/useInput";
import styled from "styled-components";

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

const Signup = () => {
	//id input
  const [id, onChangeId] = useInput("");
	//nickname input
  const [nickname, onChangeNickname] = useInput("");
  //password input
  const [password, onChangePassword] = useInput("");
  const [passwordCheck, setPasswordCheck] = useState("");
	// passwordError 초기값은 false
  const [passwordError, setPasswordError] = useState(false);
	// passowrd와 passwordCheck의 value가 다르면 passwordError를 true로
  const onChangePasswordCheck = useCallback(
    e => {
      setPasswordCheck(e.target.value);
      setPasswordError(e.target.value !== password);
    },
    [password]
  );
  //term (약관동의)
  const [term, setTerm] = useState("");
	// termError 초기값은 false
  const [termError, setTermError] = useState(false);
	// 약관동의를 한 경우 termError를 false로
  const onChangeTerm = useCallback(e => {
    setTerm(e.target.checked);
    setTermError(false); 
  }, []);
	// submit버튼을 눌렀을경우 password와 term을 한번더 확인 
  const onSubmit = useCallback(() => {
		// passowrd와 passwordCheck가 다르면 passwordError를 true로
    if (password !== passwordCheck) {
      return setPasswordError(true);
    }
		// 약관동의를 안할경우 setTermError를 true로
    if (!term) {
      return setTermError(true);
    }
    console.log(id, nickname, password);
  }, [password, passwordCheck, term]);

  return (
    <>
      <Head>
        <title>회원가입 | NodeBird</title>
      </Head>
      <AppLayout>
        <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-id"
              type="password"
              value={password}
              required
              onChange={onChangePassword}
            />
          </div>
          <div>
            <label htmlFor="user-id">비밀번호 체크</label>
            <br />
            <Input
              name="user-id"
              type="password"
              value={passwordCheck}
              required
              onChange={onChangePasswordCheck}
            />
            {passwordError && (
              <ErrorMessage>비밀번호가 일치하지 않습니다.</ErrorMessage>
            )}
          </div>
          <div>
            <Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
              말을 잘 들을 것을 동의합니다.
            </Checkbox>
            {termError && (
              <ErrorMessage>약관에 동의하셔야 합니다.</ErrorMessage>
            )}
          </div>
          <div style={{ marginTop: 10 }}>
            <Button type="primary" htmlType="submit">
              가입하기
            </Button>
          </div>
        </Form>
      </AppLayout>
    </>
  );
};

export default Signup;

0개의 댓글