Firebase

Firebase를 사용한 트위터 클론 코딩#7(Log In2)

PON_Z 2022. 7. 14. 15:32

- 이전에 계정을 생성했는데도 create account 버튼이 log in으로 바뀌지 않았었다.

  이는 App.js에서 원인을 찾을 수 있다.

 

- 어플리케이션이 로드될 때 firebase는 사용자가 로그인 되었는지 아닌지 확인할 시간이 없다.

  왜냐하면 너무 빨리 일어나기 때문이다.

  그래서 어플리케이션이 로드되자마자 로그아웃이 될 것이며 currentUser에는 아무것도 없을 것이다.

 

 

- 사용자의 로그인 상태 변화를 관찰하기 위해 docs에서 onAuthStateChanged를 사용할 것이다.

  이는 기본적으로 event listener이다.

  

 

- 코드를 작성해 준다. (App.js)

  authStated의 변화를 감지하여 로그인이 되어있으면 true 아니면 fale를 반환한다.

  그리고 setInit은 firebase 초기화가 끝났음을 알린다.

  init이 true면 Router가 로그인 되어있는지를,

  false면 초기화 중이라는 문구를 내보낸다.

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

function App() {
  // firebase가 프로그램을 초기화 하길 기다리기 위한 state
  const [init, setInit] = useState(false);
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // user의 변화를 듣고 listen
  useEffect(() => {
    authService.onAuthStateChanged((user) => {
      if(user) {
        setIsLoggedIn(true);
      }
      else {
        setIsLoggedIn(false);
      }
      setInit(true);
    });
  }, []);

/*
  console.log(authService.currentUser);
  setInterval(() => {
    console.log.authService(authService.currentUser);
  }, 2000);
  */
  return (
    <>
    {init ? <AppRouter isLoggedIn={isLoggedIn} /> : "Initializing..."}
    <footer>&copy; {new Date().getFullYear()} PONZ</footer>
    </>
  );
}

export default App;

 

- 초기화 후, 로그인이 되어있으므로 Home이 뜨는 것을 볼 수 있다.

 

- 현재는 로그아웃이 구현되있지 않기 때문에 로그아웃을 위해서는 firebase DB에서 clear object를 누르면 된다.

 

- 로그아웃 되었다!

 

- 그런데 현재 계정을 생성할 때, 이메일이 중복되거나 저번과 같이 6자리 이하의 비밀번호를 치는

  에러 같은 경우 콘솔에서만 에러를 감지하기 때문에 유저들은 에러를 인지하기 힘들다.

  그래서 에러 핸들링을 위해 Auth.js를 수정할 것이다.

 

- error state를 만들어서 에러가 발생할 시 alert로 에러 메시지를 내보내 줄 것이다.

import { createUserWithEmailAndPassword,
         signInWithEmailAndPassword,
         getAuth
       } from "firebase/auth";
import { authService } from "myFirebase";
import React, {useEffect, useState} from "react";

// for auth import
const Auth = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [newAccount, setNewAccount] = useState(true);
    const [error, setError] = useState("");

    // Input Change 감지
    const onChange = (event) => {
        //console.log(event.target.name);
        // 이벤트로부터 name을 받아서 email OR password set하기
        const {target: {name, value}} = event;
        if(name === "email") {
            setEmail(value);
        }
        else if (name === "password") {
            setPassword(value);
        }
    };

    // async로 바꿔주기
    const onSubmit = async (event) => {
        // form 제출 값이 default인 것을 방지
        event.preventDefault();
        try {
            let data;
            const auth = getAuth();
            if(newAccount) {
                // 계정 생성
                data = await createUserWithEmailAndPassword(
                    auth,
                    email,
                    password
                );
               
            }
            else {
                // 로그인
                data = await signInWithEmailAndPassword(
                    auth,
                    email,
                    password
                );
            }
            console.log(data);
        }
        catch(error) {
            // 에러탐지시 메시지 설정
            setError(error.message);
        }
       
    };

    return (
        <div>
            <form onSubmit={onSubmit}>
                <input
                    name="email"
                    type="text"
                    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"}
                />
                {error ? alert(error) : ""}
            </form>
            <div>
                <button>
                    Login with Google
                </button>
            </div>
        </div>
    );
};

export default Auth;

- 현재까지는 로그인과 계정 생성을 마음대로 할 수 없었다.

  이를 자유롭게 하지위해 문자열로 토글 버튼을 만들어 스위치 할 수 있게 코드를 작성하자.

    // newAccount의 이전 값을 가져와서 반대되는 값을 리턴
    const toggleAccount = () => setNewAccount((prev) => !prev);

    return (
        <div>
            <form onSubmit={onSubmit}>
                <input
                    name="email"
                    type="text"
                    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"}
                />
                {error ? alert(error) : ""}
            </form>
            <span
                onClick={toggleAccount}
                style={{ color: "#3F51B5" }}>
                {newAccount ? "Do you want to Log In?" : "Do you want to Create Account?"}
            </span>
            <div>
                <button>
                    Login with Google
                </button>
            </div>
        </div>
    );
};

export default Auth;

 

- 아래 문자열을 클릭하면

- 버튼이 토글 되는 것을 볼 수 있다.

- 이제 구글로 로그인 그능을 구현해 볼 것이다.

   Firebase docs의 SignWithPopup() 또는 ~redirect를 사용하면 된다.

  여기서는 SignWithPopup을 사용할 것이다.

- 위 docs을 참고하여 코드를 작성하자.

 

import { createUserWithEmailAndPassword,
         signInWithEmailAndPassword,
         getAuth,
         GoogleAuthProvider,
         signInWithPopup
       } from "firebase/auth";
import { authService } from "myFirebase";
import React, {useEffect, useState} from "react";

// for auth import
const Auth = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [newAccount, setNewAccount] = useState(false);
    const [error, setError] = useState("");

    // Input Change 감지
    const onChange = (event) => {
        //console.log(event.target.name);
        // 이벤트로부터 name을 받아서 email OR password set하기
        const {target: {name, value}} = event;
        if(name === "email") {
            setEmail(value);
        }
        else if (name === "password") {
            setPassword(value);
        }
    };

    // async로 바꿔주기
    const onSubmit = async (event) => {
        // form 제출 값이 default인 것을 방지
        event.preventDefault();
        try {
            let data;
            const auth = getAuth();
            if(newAccount) {
                // 계정 생성
                data = await createUserWithEmailAndPassword(
                    auth,
                    email,
                    password
                );
               
            }
            else {
                // 로그인
                data = await signInWithEmailAndPassword(
                    auth,
                    email,
                    password
                );
            }
            console.log(data);
        }
        catch(error) {
            // 에러탐지시 메시지 설정
            setError(error.message);
        }
       
    };

    // newAccount의 이전 값을 가져와서 반대되는 값을 리턴
    const toggleAccount = () => setNewAccount((prev) => !prev);

    // 소셜 로그인을 위한 onClick
    const onSocialClick = async (event) => {
        const {
            target: { name },
        } = event;

        let provider;
        const auth = getAuth();

        if(name === "google") {
            provider = new GoogleAuthProvider();
        }

        const data = await signInWithPopup(auth, provider);
        console.log(data);
    }

    return (
        <div>
            <form onSubmit={onSubmit}>
                <input
                    name="email"
                    type="text"
                    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"}
                />
                {error ? alert(error) : ""}
            </form>
            <span
                onClick={toggleAccount}
                style={{ color: "#3F51B5" }}>
                {newAccount ? "Do you want to Log In?" : "Do you want to Create Account?"}
            </span>
            <div>
                <button onClick={onSocialClick} name="google">
                    Login with Google
                </button>
            </div>
        </div>
    );
};

export default Auth;
 
 

- 구글로 로그인이 되었으며, 

  firebase에도 provider가 구글로 새 계정이 추가된 것을 볼 수 있다.

- ref) https://nomadcoders.co/nwitter/lectures/

728x90