react-hook-form을 사용해서 유효성 체크
설치
$npm install react-hook-form --save
watch
라는 메소드로 element를 관찰할수 있다.
watch("example")
관찰을 할 때 register로 등록을 해줘야 한다.
<inpu name="example" ref={register} />
register 안에 어떠한 식으로 유효성을 체크할지 조건을 넣어준다.
ref={register({required: true, maxlength: 10})}
유효성 체크에 걸렸을 때 에러 문구를 설정해 줍니다.
{errors.name && <p>메세지</p>}
RegisterPage.js 코드
import React, { useRef } from "react";
import { Link } from "react-router-dom";
import { useForm } from "react-hook-form";
const RegisterPage = () => {
const { register, watch, errors } = useForm({ mode: "onChange" });
const password = useRef();
password.current = watch("password");
return (
<div className="auth-wrapper">
<form>
<h1>Register</h1>
<label>Email</label>
<input
name="email"
type="email"
ref={register({ required: true, pattern: /^\S+@\S+$/i })}
/>
{errors.email && errors.email.type === "required" && (
<p>이메일은 반드시 입력해야합니다.</p>
)}
{errors.email && errors.email.type === "pattern" && (
<p>이메일이 형식에 맞지 않습니다.</p>
)}
<label>Name</label>
<input name="name" ref={register({ required: true, maxLength: 10 })} />
{errors.name && errors.name.type === "required" && (
<p>이름은 반드시 입력해야합니다.</p>
)}
{errors.name && errors.name.type === "maxLength" && (
<p>이름은 10글자를 넘길 수 없습니다.</p>
)}
<label>Password</label>
<input
name="password"
type="password"
ref={register({ required: true, minLength: 6 })}
/>
{errors.password && errors.password.type === "required" && (
<p>비밀번호는 반드시 입력해야합니다.</p>
)}
{errors.password && errors.password.type === "minLength" && (
<p>비밀번호는 6글자 이상이여야 합니다.</p>
)}
<label>PasswordConfirm</label>
<input
name="password_confirm"
type="password"
ref={register({
required: true,
validate: (value) => value === password.current,
})}
/>
{errors.password_confirm &&
errors.password_confirm.type === "required" && (
<p>비밀번호 확인은 반드시 입력해야합니다.</p>
)}
{errors.password_confirm &&
errors.password_confirm.type === "validate" && (
<p>비밀번호와 비밀번호 확인이 일치하지 않습니다.</p>
)}
<input type="submit" value="submit" />
<Link to="/login" style={{ color: "gray", textDecoration: "none" }}>
이미 아이디가 있다면...
</Link>
</form>
</div>
);
};
export default RegisterPage;
보통 javascript
에서는 getElementById
, querySelector
같은 DOM Selector 함수를 사용해서 DOM을 선택
리액트에서는 ref
라는 것을 이용해서 DOM을 선택 !
클래스 컴포넌트 : React.createRef
함수형 컴포넌트 : useRef
DOM을 직접 선택해야 할 경우들
1. 엘리먼트 크기를 가져와야 할 때
2. 스크롤바 위치를 가져와야 할 때
3. 엘리먼트에 포커스를 설정 해줘야 할 때 등등
Submit 버튼 누르면 FireBase에 이메일과 비밀번호 저장
const { register, watch, errors, handleSubmit } = useForm({
mode: "onChange",
});
const [errorFromSubmit, setErrorFromSubmit] = useState("");
const [loading, setLoading] = useState(false);
...
const onSubmit = async (data) => {
try {
setLoading(true);
let createUser = await firebase
.auth()
.createUserWithEmailAndPassword(data.email, data.password);
setLoading(false);
} catch (error) {
setErrorFromSubmit(error.message);
setLoading(false);
setTimeout(() => {
setErrorFromSubmit("");
}, 5000);
}
};
...
return (
<div className="auth-wrapper">
<form onSubmit={handleSubmit(onSubmit)}>
...
{errorFromSubmit && <p>{errorFromSubmit}</p>}
<input type="submit" value="submit" disabled={loading} />
...
유저의 photoURL에 유저마다 유니크한 이미지를 넣기위해 md5
사용
설치
$ npm install md5 --save
createUser에 updateProfile을 이용하여 이름과 사진을 추가로 넣어주었다.
const onSubmit = async (data) => {
try {
setLoading(true);
// 이메일과 비밀번호로 유저 생성
let createUser = await firebase
.auth()
.createUserWithEmailAndPassword(data.email, data.password);
>>> await createUser.user.updateProfile({
displayName: data.name,
photoURL: `http://gravatar.com/avatar/${md5(
createUser.user.email
)}?d=identicon`,
>>> });
setLoading(false);
}
코드 추가해주기
//Firebase 데이터베이스에 저장해주기
await firebase.database().ref("users").child(createUser.user.uid).set({
name: createUser.user.displayName,
image: createUser.user.photoURL,
});
회원가입을 해보면 데이터베이스에 이렇게 저장된 것을 알수 있다.
uid는 user마다 유니크한 id 값이다.
로그인 페이지는 회원가입 UI와 똑같이 만든다.
await firebase
.auth()
.signInWithEmailAndPassword(data.email, data.password);
signInWithEmailAndPassword(data.email, data.password)
를 사용하여 파이어베이스에 로그인할 이메일과 비밀번호를 준다.
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { useForm } from "react-hook-form";
import firebase from "../../firebase";
const LoginPage = () => {
const { register, errors, handleSubmit } = useForm({
mode: "onChange",
});
const [errorFromSubmit, setErrorFromSubmit] = useState("");
const [loading, setLoading] = useState(false);
const onSubmit = async (data) => {
try {
setLoading(true);
// 이메일과 비밀번호로 유저 생성
await firebase
.auth()
.signInWithEmailAndPassword(data.email, data.password);
setLoading(false);
} catch (error) {
setErrorFromSubmit(error.message);
setLoading(false);
setTimeout(() => {
setErrorFromSubmit("");
}, 5000);
}
};
return (
<div className="auth-wrapper">
<form onSubmit={handleSubmit(onSubmit)}>
<h1>Login</h1>
<label>Email</label>
<input
name="email"
type="email"
ref={register({ required: true, pattern: /^\S+@\S+$/i })}
/>
{errors.email && errors.email.type === "required" && (
<p>이메일은 반드시 입력해야합니다.</p>
)}
{errors.email && errors.email.type === "pattern" && (
<p>이메일이 형식에 맞지 않습니다.</p>
)}
<label>Password</label>
<input
name="password"
type="password"
ref={register({ required: true, minLength: 6 })}
/>
{errors.password && errors.password.type === "required" && (
<p>비밀번호는 반드시 입력해야합니다.</p>
)}
{errors.password && errors.password.type === "minLength" && (
<p>비밀번호는 6글자 이상이여야 합니다.</p>
)}
{errorFromSubmit && <p>{errorFromSubmit}</p>}
<input type="submit" value="submit" disabled={loading} />
<Link to="/register" style={{ color: "gray", textDecoration: "none" }}>
아직 아이디가 없다면...
</Link>
</form>
</div>
);
};
export default LoginPage;
App.js 코드
onAuthStateChanged
로 user가 있는지 확인!
function App() {
let history = useHistory();
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
//user가 있으면 로그인이 된 상태
if (user) {
history.push("/");
} else {
history.push("/login");
}
});
}, []);
return (
<Switch>
<Route exact path="/" component={ChatPage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
</Switch>
);
}
export default App;
useHistory
쓰려면 App
이 Router
로 둘러싸여 있어야한다.
index.js 코드
<Router>
<App />
</Router>
App.js 코드
dispatch
를 사용해서 리덕스 스토어에 넣기
setUser
라는 함수를 만들어야한다!
import { useDispatch, useSelector } from "react-redux";
function App() {
let history = useHistory();
let dispatch = useDispatch();
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
//user가 있으면 로그인이 된 상태
if (user) {
history.push("/");
>>>>>>> dispatch(setUser(user));
} else {
...
import { SET_USER } from "./types";
export function setUser(user) {
return {
type: SET_USER,
payload: user,
};
}
types.js 코드
//USER TYPES
export const SET_USER = "set_user";
import { SET_USER } from "../actions/types";
const initialUserState = {
currentUser: null,
isLoading: true,
};
export default function (state = initialUserState, action) {
switch (action.type) {
case SET_USER:
return {
...state,
//파이어베이스에서 받은 user정보를 payload에 담은거 가져오기
currentUser: action.payload,
//로그인이 잘됐으면 isLoading false로
isLoading: false,
};
default:
return state;
}
}
isLoading을 리덕스 스토어에서 가져와서 쓰려면 useSelector
사용해야한다.
App.js 코드
function App() {
const isLoading = useSelector((state) => state.user.isLoading);
...
if (isLoading) {
return <div>...loading</div>;
} else {
return (
<Switch>
<Route exact path="/" component={ChatPage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
</Switch>
);
}
}