[React] TODO LIST 만들기 (2) - Firebase로 회원가입 하기

Kylie·2022년 11월 20일
0

[React] Todo List

목록 보기
2/6
post-thumbnail
post-custom-banner

1. 들어가기전

저번 포스팅에서 이번 프로젝트에서 사용할 firebase 사용을 위한 설정을 했습니다.
이번에는 firebase로 회원가입을 해보도록 하겠습니다.


2. 목표

  • firebase 의 createUserWithEmailAndPassword 을 사용하여 계정을 생성 한다.
  • 생성된 계정을 firestore 에 저장한다.
  • 회원가입 후 로그인 페이지로 이동한다.
  • MUI을 사용하여 UI를 만든다.

3. 필요한 패키지 설치

$ 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

4. 파일 생성

먼저 회원가입과 로그인 페이지를 만들어 보겠습니다.

4.1 signUp.tsx 파일 생성

src/pages/signUp.tsx

import React from "react";

export const SignUp = () => {
    return (
        <>
            <h1>Sigin Up Page</h1>
        </>
    )
}

4.2 login.tsx 파일 생성

src/pages/login.tsx

import React from "react";

export const Login = () => {
    return (
        <>
            <h1>Login Page</h1>
        </>
    )
}

4.3 userForm styled 파일 생성

src/styles/userForm.styled.ts

import styled from "styled-components";

export const UserForm = styled.div``;

5. 라우터 설정

http://localhost:3000/signup 에 접속했을 때 회원가입 페이지가 나올 수 있도록 라우터를 설정하도록 하겠습니다.

src/routes/Router.tsx

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>
    )
}

💡 회원가입 후 바로 로그인 페이지로 이동할 예정이라 로그인 페이지에 접속할 수 있도록 미리 작성했습니다.


6. 회원가입

6.1 Interface 설정

src/interfaces/user.interface.ts

export interface UserInterface {
    uid: string,
    email: string,
    displayName: string,
    date_created: string,
}

export interface UserInputInterface {
    email: string,
    displayName?: string,
    password: string
}

6.2 회원가입 form 만들기

src/pages/signUp.tsx

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>
}

6.3 userForm styled 설정

src/styles/userForm.styled.ts

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;
  }
`;

결과

회원가입 폼을 다 만들었습니다. 지금부터 기능을 하나씩 붙여보도록 하겠습니다.


6.4 onChange

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>
}

6.5 onSubmit

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>
}



6.6 전체코드

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>
}

6.7 firebase 확인

firebase에 방금 입력한 내용이 저장된 것을 확인할 수 있습니다.




관련 firebase doc

profile
올해보단 낫겠지....
post-custom-banner

0개의 댓글