리액트-파이어베이스 (채팅 어플리케이션 만들기) #2. 인증 처리

김지원·2020년 11월 27일
2

React

목록 보기
23/31

인증 처리

회원가입 페이지 UI 만들기

아이콘 사용할 수 있는 곳

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;

useRef를 이용한 현재 password 값 갖기

보통 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;

로그인 하면 chatpage로 이동

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 쓰려면 AppRouter로 둘러싸여 있어야한다.

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 {
        
        ...
        

redux actions에 user_action.js 추가

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";

redux reducers user_reducer.js 만들기

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

0개의 댓글

관련 채용 정보