저번 포스팅에서 이번 프로젝트에서 사용할 firebase 사용을 위한 설정을 했습니다.
이번에는 firebase로 회원가입을 해보도록 하겠습니다.
- firebase 의
createUserWithEmailAndPassword
을 사용하여 계정을 생성 한다.- 생성된 계정을
firestore
에 저장한다.- 회원가입 후 로그인 페이지로 이동한다.
MUI
을 사용하여 UI를 만든다.
$ npm install react-router react-router-dom
$ npm install -D @types/react-router @types/react-router-dom
$ npm install --save styled-components
$ npm install @mui/material @emotion/react @emotion/styled
$ npm install @mui/icons-material
먼저 회원가입과 로그인 페이지를 만들어 보겠습니다.
import React from "react";
export const SignUp = () => {
return (
<>
<h1>Sigin Up Page</h1>
</>
)
}
import React from "react";
export const Login = () => {
return (
<>
<h1>Login Page</h1>
</>
)
}
import styled from "styled-components";
export const UserForm = styled.div``;
http://localhost:3000/signup
에 접속했을 때 회원가입 페이지가 나올 수 있도록 라우터를 설정하도록 하겠습니다.
import React from "react";
import {BrowserRouter, Routes, Route} from "react-router-dom";
// COMPONENTS
import {SignUp} from "../pages/signUp";
import {Login} from "../pages/login"
export const AppRouter = () => {
return (
<BrowserRouter>
<Routes>
<Route path='/signup' element={<SignUp/>}></Route>
<Route path='/' element={<Login/>}></Route>
</Routes>
</BrowserRouter>
)
}
💡 회원가입 후 바로 로그인 페이지로 이동할 예정이라 로그인 페이지에 접속할 수 있도록 미리 작성했습니다.
export interface UserInterface {
uid: string,
email: string,
displayName: string,
date_created: string,
}
export interface UserInputInterface {
email: string,
displayName?: string,
password: string
}
import React from "react";
// INTERFACE
import {UserInputInterface} from "../interfaces/user.interface";
// CSS
import {UserForm} from "../styles/userForm.styled";
import {Button, TextField} from "@mui/material";
export const SignUp = () => {
return <UserForm>
<div className={'doc-title'}>
<span>TODO LIST</span>
</div>
<article className={'user-form-article'}>
<div className={'user-form-wrap'}>
<div className={'user-form'}>
<form onSubmit={onSubmit}>
<TextField label="email" variant="outlined"
name={'email'} type={'email'}
required/>
<TextField label="displayName" variant="outlined"
name={'displayName'} type={'text'}
required/>
<TextField label="password" variant="outlined"
name={'password'} type={'password'}
required/>
<Button variant={'contained'} type={"submit"} disabled={true}>
Sign Up
</Button>
</form>
</div>
</div>
</article>
</UserForm>
}
import { styled } from "@mui/material";
export const UserForm = styled("div")`
.doc-title {
padding-top: 50px;
display: block;
width: 580px;
height: 27px;
margin: 0 auto;
background-size: 100px 80px;
font-size: 19px;
line-height: 27px;
text-align: center;
vertical-align: top;
}
.user-form-article {
box-sizing: border-box;
width: 580px;
height: 100%;
margin: 40px auto 42px;
padding: 0 69px;
border: 1px solid rgba(0, 0, 0, .12);
font-size: 12px;
}
.user-form-article > .user-form-wrap {
word-wrap: break-word;
position: relative;
padding: 10px 0px
}
.user-form {
padding: 50px;
}
.user-form > form {
display: flex;
flex-direction: column;
}
.user-form > form div {
margin : 8px 0px;
}
.user-form > form button {
margin-top: 10px;
padding: 15px;
margin-bottom: 20px;
}
`;
회원가입 폼을 다 만들었습니다. 지금부터 기능을 하나씩 붙여보도록 하겠습니다.
input에 값이 입력될 때마다 handle 하는 함수 onChange
함수를 만들어보겠습니다.
(+) Button은 모든 input에 값이 있을 때 활성화하도록 했습니다.
import React, {ChangeEvent, useState} from "react";
// INTERFACE
import {UserInputInterface} from "../interfaces/user.interface";
// CSS
import {UserForm} from "../styles/userForm.styled";
import {Button, TextField} from "@mui/material";
export const SignUp = () => {
const [inputs, setInputs] = useState<UserInputInterface>({
email: "",
displayName: "",
password: ""
});
const {email, displayName, password} = inputs;
const onChange = (e: ChangeEvent<HTMLInputElement>): void => {
const {name, value} = e.currentTarget;
setInputs({...inputs, [name]: value});
}
return <UserForm>
<div className={'doc-title'}>
<span>TODO LIST</span>
</div>
<article className={'user-form-article'}>
<div className={'user-form-wrap'}>
<div className={'user-form'}>
<form>
<TextField label="email" variant="outlined"
onChange={onChange} value={email} name={'email'} type={'email'}
required/>
<TextField label="displayName" variant="outlined"
onChange={onChange} value={displayName} name={'displayName'} type={'text'}
required/>
<TextField label="password" variant="outlined"
onChange={onChange} value={password} name={'password'} type={'password'}
required/>
<Button variant={'contained'} type={"submit"}
disabled={email.length !== 0 && displayName?.length !== 0 && password.length !== 0 ? false : true}>
Sign Up
</Button>
</form>
</div>
</div>
</article>
</UserForm>
}
form을 제출을 handle 하는 onSubmit
함수입니다.
onSubmit
를 할 때 firebase auth 와 firestore에 데이터를 저장합니다.
import React, {ChangeEvent, useState} from "react";
import {useNavigate} from 'react-router-dom'
import moment from "moment";
// FIREBASE
import {firebaseAuth, fireStoreJob} from "../initFirebase";
import {createUserWithEmailAndPassword} from "firebase/auth";
import {collection, addDoc} from "firebase/firestore";
// INTERFACE
import {UserInputInterface} from "../interfaces/user.interface";
// CSS
import {UserForm} from "../styles/userForm.styled";
import {Button, TextField} from "@mui/material";
export const SignUp = () => {
const firestore_path = 'users'; // firebase collection 이름
const navigate = useNavigate();
const onSubmit = async (e: ChangeEvent<HTMLFormElement>) => {
e.preventDefault();
await createUserWithEmailAndPassword(firebaseAuth, email, password)
.then(async (userCredential) => {
const user = userCredential.user;
console.log(user)
// 계정 생성을 하고 나면 firestore에 데이터를 저장합니다.
await addDoc(collection(fireStoreJob, firestore_path), {
uid: user.uid,
...inputs,
date_created: moment().utc().format()
})
// 모든 과정이 끝나면 login 페이지로 이동합니다.
navigate("/");
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.warn(`${errorCode} - ${errorMessage}`)
})
}
return <UserForm>
<div className={'doc-title'}>
<span>TODO LIST</span>
</div>
<article className={'user-form-article'}>
<div className={'user-form-wrap'}>
<div className={'user-form'}>
<form onSubmit={onSubmit}>
<TextField label="email" variant="outlined"
onChange={onChange} value={email} name={'email'} type={'email'}
required/>
<TextField label="displayName" variant="outlined"
onChange={onChange} value={displayName} name={'displayName'} type={'text'}
required/>
<TextField label="password" variant="outlined"
onChange={onChange} value={password} name={'password'} type={'password'}
required/>
<Button variant={'contained'} type={"submit"}
disabled={email.length !== 0 && displayName?.length !== 0 && password.length !== 0 ? false : true}>
Sign Up
</Button>
</form>
</div>
</div>
</article>
</UserForm>
}
import React, {ChangeEvent, useState} from "react";
import {useNavigate} from 'react-router-dom'
import moment from "moment";
// FIREBASE
import {firebaseAuth, fireStoreJob} from "../initFirebase";
import {createUserWithEmailAndPassword} from "firebase/auth";
import {collection, addDoc} from "firebase/firestore";
// INTERFACE
import {UserInputInterface} from "../interfaces/user.interface";
// CSS
import {UserForm} from "../styles/userForm.styled";
import {Button, TextField} from "@mui/material";
export const SignUp = () => {
const firestore_path = 'users';
const navigate = useNavigate();
const [inputs, setInputs] = useState<UserInputInterface>({
email: "",
displayName: "",
password: ""
});
const {email, displayName, password} = inputs;
const onChange = (e: ChangeEvent<HTMLInputElement>): void => {
const {name, value} = e.currentTarget;
setInputs({...inputs, [name]: value});
}
const onSubmit = async (e: ChangeEvent<HTMLFormElement>) => {
e.preventDefault();
await createUserWithEmailAndPassword(firebaseAuth, email, password)
.then(async (userCredential) => {
const user = userCredential.user;
console.log(user)
await addDoc(collection(fireStoreJob, firestore_path), {
uid: user.uid,
...inputs,
date_created: moment().utc().format()
})
navigate("/login");
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.warn(`${errorCode} - ${errorMessage}`)
})
}
return <UserForm>
<div className={'doc-title'}>
<span>TODO LIST</span>
</div>
<article className={'user-form-article'}>
<div className={'user-form-wrap'}>
<div className={'user-form'}>
<form onSubmit={onSubmit}>
<TextField label="email" variant="outlined"
onChange={onChange} value={email} name={'email'} type={'email'}
required/>
<TextField label="displayName" variant="outlined"
onChange={onChange} value={displayName} name={'displayName'} type={'text'}
required/>
<TextField label="password" variant="outlined"
onChange={onChange} value={password} name={'password'} type={'password'}
required/>
<Button variant={'contained'} type={"submit"}
disabled={email.length !== 0 && displayName?.length !== 0 && password.length !== 0 ? false : true}>
Sign Up
</Button>
</form>
</div>
</div>
</article>
</UserForm>
}
firebase에 방금 입력한 내용이 저장된 것을 확인할 수 있습니다.