본문 바로가기

Projects/React + Firebase 링크드인 클론

#4. 로그인 부분 구현 | Login.js

로그인 기능을 구현해보자

Firebase와 Redux 세팅을 마쳤으니, 이제 로그인 부분을 구현해보자. Login.js로 컴포넌트를 만든다.

 

import React, { useState } from 'react'
import { useDispatch } from 'react-redux';
import { login } from './features/userSlice';
import { auth } from './firebase';
import './Login.css'

function Login() {

	//실제로 회원가입과 로그인 정보를 담는 부분은 아니다
    //우리가 로그인 창에 글자를 입력 시 이를 UI상에 보여주기 위한 State들이다
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [name, setName] = useState("");
    const [profilePic, setProfilePic] = useState("");
    
    //Reducer를 작동시키기 위한 dispatch 사용
    const dispatch = useDispatch();

	//Sign In 버튼을 누를 때 작동할 로그인 기능
    //입력한 값들을 element 객체로 전달받음
    const loginToApp = (e) => {
    	
        //Enter키로 함수가 작동하는 걸 방지
        e.preventDefault();
        
        //Firebase의 auth 라이브러리로 입력받은 이메일과 비밀번호로 로그인
        auth.signInWithEmailAndPassword(email, password)
        
        //로그인한 정보들을 dispatch에 담아서 보냄
        //이 정보들로 reducer 중 login 기능 실행
        //login reducer는 전달받은 정보들(payload)을 user에 저장하는 기능
        .then((userAuth)=>{
            dispatch(
                login({
                    email: userAuth.user.email,
                    uid: userAuth.user.uid,
                    displayName: userAuth.user.displayName,
                    photoUrl: userAuth.user.photoURL,
                })
            );
        })
        .catch(error => alert(error));
    };
    
    //Register Now 글자를 누를 때 작동할 회원가입 기능
    const register = () => {
    
    	//회원가입 시 이름이 입력되어 있지 않다면 경고문을 띄워줌
        if (!name) {
            return alert('Pleaser enter a full name!');
        }

		//Firebase의 auth 라이브러리로 전달받은 이메일, 패스워드로 계정 생성
        auth.createUserWithEmailAndPassword(email, password)
        
        //입력받은 정보들로 Firebase에 이름, 프로필 이미지 정보 생성
        .then((userAuth)=>{
            userAuth.user.updateProfile({
                displayName: name,
                photoURL: profilePic
            })
            
            //동시에 입력받은 정보들을 담아, reducer 중 login 부분 작동
            //login reducer는 전달받은 정보들을 user에 저장해줌
            .then(()=>{
                dispatch(
                    login({
                        email: userAuth.user.email,
                        uid : userAuth.user.uid,
                        displayName: name,
                        photoURL: profilePic
                    })
                );
            });
        }).catch((error) => alert(error));
    };
    
    return (
    	//로그인 화면 구현
        <div className='login'>
        	//링크드인 로고
            <img src="https://cdn.worldvectorlogo.com/logos/linkedin.svg" alt="" />
            
            //회원가입, 로그인 정보 입력 부분
            <form action="">
            	//회원정보를 입력하면, 입력한 정보가 바로바로 눈에 보이게 설정
                //element 객체를 사용하여, 입력한 정보들이 State로 실시간 저장되어,
                //Input 창에 자동으로 뜨게 됨
                <input value={name} onChange={(e)=>{setName(e.target.value)}} placeholder="Full name (required if registering)" type="text" />
                <input value={profilePic} onChange={(e)=>{setProfilePic(e.target.value)}} placeholder="Profile pic URL (optional)" type="text" />
                <input value={email} onChange={(e)=>{setEmail(e.target.value)}} placeholder="Email" type="email" />
                <input value={password} onChange={(e)=>{setPassword(e.target.value)}} placeholder="Password" type="password" />
                
                //Sign in 버튼을 누르면 로그인 함수 작동
                <button type="submit" onclick={loginToApp} >Sign In</button>
            </form>

            <p>
                Not a member?{" "}
                //Register Now 글자를 누르면 회원가입 함수 작동
                <span className="login__register" onClick={register}>Register Now</span>
            </p>
        </div>
    )
}

export default Login

 

Login.js에 굉장히 많은 코드들이 사용되었는데, UI 부분을 제외하고 실제로 Event를 Handling하는 부분은 두 가지 기능만으로 이루어져 있다.

 

1) 로그인을 하든, 회원가입을 하든, 회원 정보를 가지고 Firebase에 계정 가입 혹은 로그인을 진행한다.

2) 동시에 이러한 회원정보들을 dispatch로 전달하여 reducer가 해당 정보들을 user라는 state에 저장할 수 있도록 한다.

 

즉 Firebase의 auth로 로그인을 하면서도, 동시에 로그인한 정보들은 Redux에 전달되어, 다른 곳에서도 user 정보를 사용할 수 있도록 하는 것이다. 이렇게 user 정보를 저장해놓는다면, Login이 될 때만 메인서비스가 보여지도록 설정할 수 있다. App.js의 코드를 다시 살펴본다.

 

function App() {

  //로그인이나 회원가입 시 저장한 정보들을 Selector로 불러온다
  const user = useSelector(selectUser);
  
  //login 혹은 logout reducer를 작동시키기 위해 dispatch 기능을 가져온다
  const dispatch = useDispatch();

  //링크드인 사이트를 킬 때 작동하는 부분
   useEffect(()=>{
   
   //Firebase 상에서 로그인이 되어 있다면
    auth.onAuthStateChanged((userAuth)=>{
      if (userAuth) {
      	
        //로그인한 정보들을 login reducer로 redux의 user에 저장한다
        dispatch(login({
          email: userAuth.email,
          uid: userAuth.uid,
          displayName: userAuth.displayName,
          photoUrl: userAuth.photoURL
        }))
      }else {
        //Firebase 상에서 로그인이 되어 있지 않다면
        //logout reducer를 작동시켜, redux 내의 user 정보를 지워준다(null로 만든다)
        dispatch(logout());
      }
    })
   },[]);

  return (
    <div className="app">
      
      <Header />

	  //Redux의 user에 정보가 없다면
      {!user 
      
      //로그인 화면을 띄워주고
       ? (<Login />) 
       
       //user 정보가 있다면, 메인화면을 보여준다
       : (
        <div className="app__body">
          <Sidebar />
          <Feed />
          <Widgets />
        </div>
       ) }

    </div>
  );
}

export default App;

Firebase의 auth 라이브러리는 로그인 여부를 판별할 수 있도록 해주는 도구다. 헌데 실제 user 정보를 담아내기 위해서는 Redux가 필요하다. 그래서 dispatch로 user 정보를 보내 login reducer가 redux 내의 user에 유저들의 정보를 담아내는 것이다.

 

이렇게 Redux에 로그인한 유저 정보를 담아낸다면, 이것을 JSX에서 사용할 수 있다. 즉, return 부분을 보면, Redux의 user에 정보가 있는지 없는지에 따라 메인 화면을 보여줄지, 안 보여줄지를 선택할 수 있다.