본문 바로가기
Web Service/React

[트위터 클론 코딩] #3. LogIn/Out-2

by junnykim 2022. 3. 31.

~2.6까지의 강의

 

파이어베이스 공식문서에 가면 많은 것이 있는데, 우리는 Emailauthprovier을 보아야한다.

여기에 가보면, email과 password로 사용자를 생성하는 것과, 인증하는 것에 대해서 나와있다.

 

Auth.js

import { authService } from 'fbase';
import React,{useState} from 'react';

const Auth = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [newAccount, setNewAccount] = useState(true);
    const onChange = (event) => {
      const {
        target: { name, value },
      } = event;
      if (name === "email") {
        setEmail(value);
      } else if (name === "password") {
        setPassword(value);
      }
    };
    const onSubmit = async (event) => {
        try {
            let data;
            if (newAccount) {
              data = await authService.createUserWithEmailAndPassword(
                email,
                password
              );
            } else {
              data = await authService.signInWithEmailAndPassword(email, password);
            }
            console.log(data);
          } catch (error) {
            console.log(error);
          }
    };
    return (
      <div>
        <form onSubmit={onSubmit}>
          <input
            name="email"
            type="email"
            placeholder="Email"
            required
            value={email}
            onChange={onChange}
          />
          <input
            name="password"
            type="password"
            placeholder="Password"
            required
            value={password}
            onChange={onChange}
          />
          <input type="submit" value={newAccount ? "Create Account" : "Log In"} />
        </form>
        <div>
          <button>Continue with Google</button>
          <button>Continue with Github</button>
        </div>
      </div>
    );
  };
export default Auth;

우리는 email 주소와 password로 연결된 새로운 유저 계정을 만들기 위해 createUserWithEmailAndPassword을 사용할 것이다. 즉, 이것은 email과 password로 만드는 것이다.

 

signInWithEmailAndPassword를 사용하면, 성공적으로 만들면 어플리케이션에 로그인 될 것이다.

 

우리는 form을 두개정도 만들어서 계정이 있는지 없는지 분류할 수 있는데, 

가장 쉬운 방법은 state를 생성하는 것이다.

즉 newAccount의 초기값이 true이기 때문에 처음에는 Create Acoount가 보이지만,

생성된 이후에는 Login이 보이도록 한다.

 

이런 식으로 계정 생성 확인


우리의 어플리케이션이 로드될 때, 파이어베이스는 너무 빨리 일어난 일이라 로그인 되는지 아닌지 모른다.

그래서 어플리케이션이 실행 되자마자 바로 로그아웃된다.

 

App.js

import React, { useState, useEffect } from "react";
import AppRouter from "components/Router";
import { authService } from "fbase";


function App() {
  const [init, setInit] = useState(false);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  useEffect(() => {
    authService.onAuthStateChanged((user) => {
      if (user) {
        setIsLoggedIn(true);
      } else {
        setIsLoggedIn(false);
      }
      setInit(true);
    });
  }, []);
  return (
    <>
      {init ? <AppRouter isLoggedIn={isLoggedIn} /> : "Initializing..."}
      <footer>&copy; {new Date().getFullYear()} Nwitter</footer>
    </>
  );
}

export default App;

 

즉, 시작할때는 사용자가 로그인 되지 않은 상태이다.

그래서 우리는 useEffect를 사용해 useState하고 isLoggedIn을 할 것이다. 

onAuthStateChanged는 Callback을 표시한다. 즉, 로그인이 되었는지 안되었는지 확인할 수 있다. 실제로 로그인, 로그아웃되는지 모르기 때문에, 초기값은 false로 해준다.

 

실행시키면, 로그인 되었다는 것을 확인할 수 있다.

 

Auth.js

import { authService } from 'fbase';
import React,{useState} from 'react';

const Auth = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [newAccount, setNewAccount] = useState(true);
    const [error, setError] = useState("");
    const onChange = (event) => {
      const {
        target: { name, value },
      } = event;
      if (name === "email") {
        setEmail(value);
      } else if (name === "password") {
        setPassword(value);
      }
    };
    const onSubmit = async (event) => {
        try {
            let data;
            if (newAccount) {
              data = await authService.createUserWithEmailAndPassword(
                email,
                password
              );
            } else {
              data = await authService.signInWithEmailAndPassword(email, password);
            }
            console.log(data);
          } catch (error) {
            setError(error.message);
          }
    };
    const toggleAccount = () => setNewAccount((prev) => !prev);
    return (
      <div>
        <form onSubmit={onSubmit}>
          <input
            name="email"
            type="email"
            placeholder="Email"
            required
            value={email}
            onChange={onChange}
          />
          <input
            name="password"
            type="password"
            placeholder="Password"
            required
            value={password}
            onChange={onChange}
          />
          <input
          type="submit"
          value={newAccount ? "Create Account" : "Sign In"}
        />
        {error}
        </form>
        <span onClick={toggleAccount}>
        {newAccount ? "Sign In" : "Create Account"}
        </span>
        <div>
          <button>Continue with Google</button>
          <button>Continue with Github</button>
        </div>
      </div>
    );
  };
export default Auth;

 

error가 생기면, 그 error가 뭐든 SetError가 실행되고, 그 error를 보여준다.


이제 구글과 깃허브로 로그인을 구현해보자. 우리는 pop-up으로 할 것이다.

const onSocialClick = async (event) => {
        const {
          target: { name },
        } = event;
        let provider;
        if (name === "google") {
          provider = new firebaseInstance.auth.GoogleAuthProvider();
        } else if (name === "github") {
          provider = new firebaseInstance.auth.GithubAuthProvider();
        }
        const data = await authService.signInWithPopup(provider);
        console.log(data);
      };
      
      
      <div>
            <button onClick={onSocialClick} name="google">
                Continue with Google
            </button>
            <button onClick={onSocialClick} name="github">
                Continue with Github
            </button>
        </div>

 

먼저, provider를 만들어야 한다. 

앞에서 미리 만들어둔 buttom마다 이름과 함수를 만든다.

함수의 이름은 onSocialClick이고, event를 받는다.

더보기
import { authService, firebaseInstance } from 'fbase';
import React,{useState} from 'react';

const Auth = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [newAccount, setNewAccount] = useState(true);
    const [error, setError] = useState("");
    const onChange = (event) => {
      const {
        target: { name, value },
      } = event;
      if (name === "email") {
        setEmail(value);
      } else if (name === "password") {
        setPassword(value);
      }
    };
    const onSubmit = async (event) => {
        try {
            let data;
            if (newAccount) {
              data = await authService.createUserWithEmailAndPassword(
                email,
                password
              );
            } else {
              data = await authService.signInWithEmailAndPassword(email, password);
            }
            console.log(data);
          } catch (error) {
            setError(error.message);
          }
    };
    const toggleAccount = () => setNewAccount((prev) => !prev);

    const onSocialClick = async (event) => {
        const {
          target: { name },
        } = event;
        let provider;
        if (name === "google") {
          provider = new firebaseInstance.auth.GoogleAuthProvider();
        } else if (name === "github") {
          provider = new firebaseInstance.auth.GithubAuthProvider();
        }
        const data = await authService.signInWithPopup(provider);
        console.log(data);
      };

    return (
      <div>
        <form onSubmit={onSubmit}>
          <input
            name="email"
            type="email"
            placeholder="Email"
            required
            value={email}
            onChange={onChange}
          />
          <input
            name="password"
            type="password"
            placeholder="Password"
            required
            value={password}
            onChange={onChange}
          />
          <input
          type="submit"
          value={newAccount ? "Create Account" : "Sign In"}
        />
        {error}
        </form>
        <span onClick={toggleAccount}>
        {newAccount ? "Sign In" : "Create Account"}
        </span>
        <div>
            <button onClick={onSocialClick} name="google">
                Continue with Google
            </button>
            <button onClick={onSocialClick} name="github">
                Continue with Github
            </button>
        </div>
      </div>
    );
  };
export default Auth;

 

이를 사용하기 위해 fbase로 가서 export해주어야 한다.

fbase.js

import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
import "firebase/compat/storage";

const firebaseConfig = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_AUTH_DOMAIN,
    projectId: process.env.REACT_APP_PROJECT_ID,
    storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_MESSAGIN_ID,
    appId: process.env.REACT_APP_APP_ID,
  };

//firebase.initializeApp(firebaseConfig); 이거 쓰면 오류나서 밑처럼 써야함

export default firebase.initializeApp(firebaseConfig);
export const firebaseInstance = firebase;
export const authService = firebase.auth();

 

각각 버튼 눌렀을 떄의 모습

 

 


home에는 tweet을 쓸 수 있는 형태가 되어야하므로, navigation을 만들어야 한다.

 

Navigation.js

import React from "react";
import { Link } from "react-router-dom";

const Navigation = () => (
  <nav>
    <ul>
      <li>
        <Link to="/">Home</Link>
      </li>
      <li>
        <Link to="/profile">My Profile</Link>
      </li>
    </ul>
  </nav>
);
export default Navigation;

우리는 Home, My Profile 둘 다 갈 수 있다.

실행시

 

Router.js

import React, { useState } from "react";
import {
  HashRouter as Router,
  Route,
  Switch,
  Redirect,
} from "react-router-dom";
import Auth from "routes/Auth";
import Home from "routes/Home";
import Profile from "routes/Profile";
import Navigation from "components/Navigation";


const AppRouter = ({ isLoggedIn }) => {
  return (
    <Router>
      {isLoggedIn && <Navigation />}
      <Switch>
        {isLoggedIn ? (
          <>
            <Route exact path="/">
              <Home />
            </Route>
            <Route exact path="/profile">
              <Profile />
            </Route>
          </>
        ) : (
          <>
            <Route exact path="/">
              <Auth />
            </Route>
          </>
          
        )}
      </Switch>
    </Router>
  );
};
export default AppRouter;

 

우리의 Route에는 Profile이 없기 때문에 수정해주어야 한다.

이제, 프로필에서 로그아웃하는 버튼을 만들어준다.

 

Profile.js

import React from "react";
import { authService } from "fbase";
import { useHistory } from "react-router-dom";

export default () => {
    const history = useHistory();
    const onLogOutClick = () => {
      authService.signOut();
      history.push("/");
    };
    return (
      <>
        <button onClick={onLogOutClick}>Log Out</button>
      </>
    );
  };

 

authService가 필요하기 때문에 onLogOutClick을 만든다. 

로그아웃을 했을 때 url을 변경하도록, push를 사용해 이전으로 돌아가도록 한다.

 

 

댓글