yarn add react-hook-form@6 (현재 7버젼까지 나왔음, 개인적으로는 아직 6이 편함)
밑에는 회원가입 폼이지만, 대부분의 input 요소에 사용하면 좋은 라이브러리.
select 느 radio 도 react-hook-form 으로 될 뿐 아니라 css library 도 잘 적용됨.
import React, { useState, useRef } from "react";
import { useForm } from "react-hook-form";
import axios from "axios";
function register() {
const { register, watch, errors, handleSubmit } = useForm(); // useForm({ mode: "onChange" });
// console.log(watch("email"));
const userpwd = useRef();
userpwd.current = watch("userpwd");
const [loading, setLoading] = useState(false);
const onSumit = async (data) => {
setLoading(true);
console.log(data);
const { email, name, userpwd, phone } = data;
try {
const response = await axios.post("/api/user/user", {
email,
name,
userpwd,
phone,
});
console.log(response);
} catch (error) {
alert(error.response.data);
}
setLoading(false);
};
return (
<div style={{ width: "1024px", margin: "50px auto" }}>
<form onSubmit={handleSubmit(onSumit)}>
<label>Name</label>
<input
name="name"
type="text"
placeholder="EX) 홍길동"
ref={register({
required: true,
pattern: /^[가-힣]{2,7}$/,
})}
/>
{errors.name && errors.name.type === "required" && (
<p>이름을 입력해주세요.</p>
)}
{errors.name && errors.name.type === "pattern" && (
<p>이름 형식에 맞지 않습니다. 한글로 올바르게 이름을 입력해주세요.</p>
)}
<label>Email</label>
<input
name="email"
type="email"
placeholder="EX ) mindcrying@naver.com"
ref={register({
required: true,
pattern:
/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i,
})}
/>
{errors.email && <p>이메일을 입력해주세요.</p>}
<label>Phone</label>
<input
name="phone"
type="number"
placeholder="연락처는 숫자로만 입력해주세요. ex) 01012345678"
ref={register({
required: true,
pattern: /(^02.{0}|^01.{1}|[0-9]{3})([0-9]+)([0-9]{4})/g,
})}
/>
{errors.phone && (
<p>연락처는 01012345678 처럼 숫자로만 입력해주세요.</p>
)}
<label>Password</label>
<input
name="userpwd"
type="password"
ref={register({
required: true,
pattern:
/(?=.*\d{1,50})(?=.*[~`!@#$%\^&*()-+=]{1,50})(?=.*[a-zA-Z]{2,50}).{8,16}$/,
})}
/>
{errors.userpwd && errors.userpwd.type === "required" && (
<p>비밀번호를 입력해주세요.</p>
)}
{errors.userpwd && errors.userpwd.type === "pattern" && (
<p>
비밀번호는 8~16자로 영문 소문자, 숫자, 특수기호를 조합해서
사용하세요.
</p>
)}
<label>Password Confirm</label>
<input
name="userpwd_confirm"
type="password"
ref={register({
required: true,
validate: (value) => value === userpwd.current,
})}
/>
{errors.userpwd_confirm &&
errors.userpwd_confirm.type === "required" && (
<p>비밀번호 확인을 해주세요.</p>
)}
{errors.userpwd_confirm &&
errors.userpwd_confirm.type === "validate" && (
<p>비밀번호가 일치하지 않습니다.</p>
)}
<input type="submit" disabled={loading} />
</form>
</div>
);
}
export default register;
인풋으로 보통은 onChange 이벤트로 통제를 하거나,
useInput 이라는 커스텀 훅을 한번 만들어두고, 사용하는 경우가 많았으나,
아무래도 react-hook-form 으로 사용한 후에는,
그런 번거러운 짓을 굳이 할필요가 없다고 할 수 있다.
로그인, 게시판 등을 만들 때도 유용하고 그외에도 유용하다고 할 수 있겠다.
리액트를 사용한다면 적극 사용할만한 매우 매우 좋은 라이브러리! (성능도 좋다.)
아래는 현재 next-auth 사용 중, next-auth 는 소셜로그인이 매우 편리하게 되있는
반면에, 직접 회원가입을 받는 부분은 모두 손수 작업을 해야해서
시간에 쫒겨서 비밀번호만 crypto 로 최대한 암호화 해서,
만들어둔 api 이다. 최적화된 코드는 아니니까 혹시나 이 포스트를 보신 분 중
그대로 갖다쓰려는 분들은 좀 더 나은 코드를 구글링 하는 것을 추천한다
(이 글에 이 내용을 넣는 것은 다음에 내가 좀 더 참고할 목적으로
적어둔다.)
현재 몽구스의 모델에, email 은 unique 로 설정되어있는데,
이미 사용자가 존재할 경우, 11000 에러메세지를 던져주는데 그걸 저렇게
클라이언트에 보내서, alert 메세지를 던져주었다.
import createHandler from "@/middleware";
import Post from "@/models/post";
import User from "@/models/user";
import crypto from "crypto";
const handler = createHandler();
handler.post(async (req, res) => {
crypto.randomBytes(64, (err, buf) => {
crypto.pbkdf2(
req.body.userpwd,
buf.toString("base64"),
100000,
64,
"sha512",
(err, key) => {
req.body.userpwd = key.toString("base64");
req.body.salt = buf.toString("base64");
var users = new User(req.body);
users
.save()
.then((user) => {
return res.status(200).json({ data: users });
})
.catch((error) => {
error.code === 11000
? res
.status(400)
.send(
"이미 사용자가 있는 이메일입니다. 메일은 고유해야합니다. 다른 메일을 등록해주세요."
)
: res
.status(400)
.send(
"다시 한번 시도해주세요. 반복해서 이상이 생길 시 카톡으로 알려주세요."
);
});
}
);
});
});
현재, 클라이어트에서 정규식 등, 점검을 하고,
백단에서는 이메일이 존재하는 지 여부만 체크하고, 저장을 하게 되어있다.
보통의 실무에서는 클라이언트-백단 모두 검증로직을 돌리는 경우가 많지만, 서브프로젝트라
간단하게 암호화만 신경쓰고 패스!
모델
import mongoose, { Schema } from "mongoose";
const MODEL_NAME = "User";
const schema = new Schema(
{
email: {
type: String,
required: true,
unique: [true, "email must be unique"],
},
userpwd: String,
phone: String,
salt: String,
name: String,
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post",
},
],
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment",
},
],
image: String,
createdAt: Date,
updateAt: Date,
},
{
timestamps: true,
}
);
export default mongoose.models[MODEL_NAME] ||
mongoose.model(MODEL_NAME, schema, "users");