Firebase는 프론트엔드 개발자가 사용자 인증, 저장 및 데이터베이스 생성과 같은
일반적인 백엔드 작업을 구현할 수 있는 꽤 인기있는 BaaS (backend-as-a-service) 입니다.
그리고 Redux 는 JavaScript Application 을 위한 예측가능한 상태 컨테이너이며, Application 의
상태를 보다 효율적으로 관리하는데 사용됩니다, 요즘은 React 와 함께 사용되고 있죠, 그렇다고 해서
React 하고만 사용되는것이 아닌 다른 프레임워크와도 충분히 사용할 수 있습니다.
React-Redux-Firebase는 Firebase용 Redux 바인딩을 제공하여 Firebase를 Redux 및 React와
함께 더 쉽게 사용할 수 있도록 하는 라이브러리입니다.
또한 일부 Firebase 기능을 더 쉽게 구현할 수 있도록 몇 가지 Hooks가 함께 제공되기도 합니다.
이 로직을 구현하기 위해서는 몇가지 전제조건이 필요합니다.
네가지 조건중에 하나라도 만족하지 못한다면 해당 글을 읽는데 어려움이 있을 수 있으니, 먼저 선행학습 후
이 글을 읽는것을 추천합니다. (저도 이 글 쓰려고 공부했습니다.. 하하)
리액트 프로젝트를 만들어줍니다.
npx create-react-app login-test --template redux
를 터미널에 입력하고 실행하면, 기존 리액트에 리덕스까지 동시에 설치됩니다.
리액트 폴더가 만들어지면, cd
로 해당 폴더로 진입합니다. 그리고 추가로 몇가지를 더 설치하겠습니다.
npm install --save react-redux-firebase firebase
npm install --save redux react-redux
npm install --save redux-firestore@latest
npm install react-router-dom
위의 입력들은 내용을 보면 알겠지만, react - redux - firebase 간의 연결을 위한 설정이라고
이해하면 될것 같습니다.
위의 설치가 모두 끝났다면, 이번에는 firebase 를 세팅해 보겠습니다.
Thanks to. ( firebase 설치 안내 블로그 )
이곳에서 설명하는대로 따라서 새로운 프로젝트를 하나 작성해 보겠습니다.
이런 페이지로 이동했다면, 성공적으로 프로젝트를 생성한것입니다.
이제, 왼쪽의 사이드바에서 Authentication 을 찾아 이동하겠습니다.
시작하기 버튼을 클릭합니다.
해당 화면에서, 우리는 구글로그인과 일반 이메일 로그인을 구현할 예정이니까 이메일/비밀번호 와
Google 을 클릭하여 사용권한을 설정하겠습니다.
구글탭에서 프로젝트 지원 이메일은 자신의 이메일을 적으면 됩니다.
이렇게 사용권한 설정이 끝났습니다.
이제 다음으로 FireStore 로 이동하겠습니다.
데이터베이스 만들기 를 클릭합니다.
프로덕션 모드와 테스트 모드가 있는데, 지금은 테스트 모드를 선택하겠습니다.
이후에 코드를 변경해서 프로덕션 모드로도 변화를 줄 수 있다고 합니다.
성공적으로 firestore 가 생성이 되었습니다. 그 다음 규칙 으로 이동하겠습니다.
해당 드래그되어있는 부분을 지우고 나타나는 게시를 눌러 수정을 해줍니다.
다음, 좌측 상단에 있는 옵션 아이콘을 클릭해서 프로젝트설정 으로 들어갑니다.
이곳에서는 우리가 만든 firebase 가 어디서 작동할지를 설정합니다.
하단의 내 앱으로 가서, 안드로이드 ,ios, 웹 중 웹 을 클릭하겠습니다. </> 표시 입니다.
진행창이 보이면, 만들 앱의 닉네임을 설정 하고 체크박스를 클릭하고 계속해서 진행합니다.
콘솔로 이동될때까지 '계속' 버튼을 클릭 해주면 됩니다.
콘솔로 이동이 되고난 후 하단으로 스크롤을 하면 보이는 화면이
이 화면이고, 현재 선택되어있는 구성 탭 의 코드가 잘 보인다면 성공적으로 끝난것입니다.
이제 나중에 저 구성 탭에 있는 코드를 사용할것입니다. 코드를 잘 복사해 두거나, 해당 페이지를 닫지않습니다.
이제 모든 준비가 끝났고, 에디터로 넘어가겠습니다.
일단 에디터로 돌아가서 정리를 한번 해주겠습니다. 필요없는 파일들을 삭제 합니다.
App.test.js
logo.svg
serviceWorker.js
setupTests.js
App.js (내부 파일만)
파일을 삭제 해 주겠습니다.
그리고 이 외의 파일들 안에서 삭제된 파일들이 import 되어 사용되고 있는 부분을 전부 삭제해주겠습니다.
그리고 나서 App.js 안의 <div>
태그 안의 코드를 전부 삭제하고 간단한 text 를 작성해서
정상적으로 구현이 되는지를 확인합니다. npm start
로 실행합니다.
정상적으로 출력이 되는것을 확인했다면, 이제 시작할 준비가 되었습니다.
만약, 오류가 뜬다면 해당 오류를 잘 읽어보고 지우지 않은 코드가 있는지 확인합니다.
이 프로젝트의 목적은 로그인 구현 이라는 기능이기 때문에, 다른 디자인 없이 간단하게만 구현합니다.
현재 출력이 되는 App.js 는 메인 화면 즉, 로그인이 되면 나오는 화면일테니. 텍스트를 바꿔줍니다.
이제부터 만들 로그인 창에서 로그인이 정상적으로 완료된다면, 이 페이지가 보이게 될겁니다.
firebase.js 파일을 생성합니다. 그리고 아까 복사해 두었던 firebase 의 코드를 복붙합니다.
npm i firebase
를 입력하고 firebase 를 설치합니다.
그리고 firebase 를 import 해주겠습니다.
이 다음에는 기본적인 firebase app 코드와, 우리가 설정했던 기본 이메일,
그리고 구글로 로그인하는 코드를 작성할겁니다.
const firebaseApp = firebase.initializeApp(firebaseConfig);
// firebase app 관련 코드
const auth = firebase.auth()
// 기본 이메일 로그인을 위한 코드
const provider = new firebase.auth.GoogleAuthProvider()
// 구글 로그인을 위한 코드
const db = firebaseApp.firestore()
// 데이터베이스 관련 코드
export {auth, provider}
export default db
// 위에서 설정한 변수들을 export 하는 코드
위의 코드들을 밑에다 붙여넣어줍니다.
시간이 지나면 몇몇 코드들의 text color 가 바뀔겁니다, 아직 firebase 가 적용되지 못한상태입니다.
진행하는데는 크게 문제가 없으니 다음으로 넘어가겠습니다.
(firebase 가 정상적으로 적용된 상태)
일단 features 폴더 안에있는 파일 중
counterSlice.js
만 남기고 모두 삭제하고, 모든 파일을 counter 파일에서 빼 features 폴더에 담습니다.
counter 폴더는 사라집니다.
현재 보이는게 리덕스의 기본 세팅이라고 할 수 있겠습니다. 우리는 여기서 몇가지만 삭제합니다.
아래의 코드로 덮어씌웁니다. 기존 코드에서 몇가지만 삭제하고 정리한 코드입니다.
import { createSlice } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export const selectCount = (state) => state.counter.value;
export default counterSlice.reducer;
이제 여기서 코드를 변경하겠습니다.
createSlice() -> initialState: { user: null }
로그인의 초기값은 '모르는' 사용자이기 때문에 null 값을 부여합니다.
reducers: increment -> login , decrement -> logout , incrementByAmount 삭제
로그인의 기능에는 로그인, 로그아웃만 필요하기 때문에 위에서부터 변경하고 마지막 세번째는
삭제합니다. 내부의 요소도 변경할겁니다.
생성한 login 과 logout 은 reducer 가 생성한 action 입니다. action 이 key 값으로 들어온거죠
바로 createSlice( ) 때문에 가능하게 됬습니다.
어디선가 객체로 dispatch 되어 온 action 을 createSlice 가 받게 됩니다. 그리고 reducer 는
들어온 객체가 login 인지, logout 인지 구별해서 해당 기능을 실행하게 됩니다.
login, logout 내부 변경
login 부분의 인자에 action 을 추가해 준다. 그리고 state.value 가 아닌, state.user 로
변경해준다, login 에는 그 값을 action.payload 를 할당한다.
action.payload 는 특정 컴포넌트에서 받아온 정보들을 현재 user의 상태에 추가하겠다는 의미입니다.
logout 은 user 의 상태를 초기상태로 되돌리면 됩니다. null 을 할당시킵니다.
state.user 의 user 정보를 전달해야한다. 나중에 userSelector 로 상태를 변경할겁니다.
이제 store 로 이동합니다.
삼항연산자를 이용해서 로그인 화면과, 로그인 성공시 보이는 화면을 구별시켜보겠습니다.
App.js 로 이동합니다.
user의 상태가 존재한다면 로그인 성공페이지를, 그렇지 않다면 로그인 화면을 보이게 해야합니다.
그 전에, 로그인 성공페이지를 App.js 에 단순한 h1 태그로 작성되있어서 복잡해 보일 수 있으니.
Main.js 파일을 만들어 그 안에 로그인 성공 페이지를 만들어줍니다.
Main.js 파일 생성
App.js 파일에서 삼항연산자를 이용해, user 가 존재하면 Main.js 로, 그렇지 않다면 Login.js로
이동하게 합니다, 그리고 user의 출처는 useSelector 를 이용해 userSlice 에서 만들어놓은
selectUser 를 가져온것입니다.
그럼 이제 Login.js 로 이동해 로그인 페이지를 구현하겠습니다.
Login.js 의 구성은 꽤 길기때문에 코드에 주석을 달아 설명을 하겠습니다.
import React, { useState } from 'react';
import { auth, provider } from "./firebase";
// firebase 에서 export 한 두가지의 변수 (일반, 구글) 를 가져옵니다.
import './Login.css'
function Login() {
const [email, setEmail] = useState("");
// email 값의 변화를 useState 로 저장합니다.
const [password, setPassword] = useState("");
// password 값의 변화를 useState 로 저장합니다.
const signIn = () => {
auth.signInWithPopup(provider).catch((e) => alert(e.message));
};
// 로그인창 을 호출하는 코드
const handleLogin = (e) => {
e.preventDefault();
auth.signInWithEmailAndPassword(email, password)
.then((auth) => {
console.log(auth);
})
.catch((e) => alert(e.message))
setEmail("");
setPassword("");
}
// 로그인 버튼 클릭시 실행되는 함수
const handleRegister = (e) => {
e.preventDefault();
auth.createUserWithEmailAndPassword(email, password)
.then((auth) => {
if (auth) {
console.log(auth)
}
})
.catch((e) => alert(e.message))
setEmail("");
setPassword("");
};
// 회원가입 버튼 클릭시 실행되는 함수
return (
<div className="login">
<div className="login_container">
<div className="login_desc">
<p> 로그인 화면입니다</p>
</div>
<div className="login_auth">
<div className="login_authOptions">
<div className="login_authOption">
<img className="login_gooogleAuth"
src="https://media-public.canva.com/MADnBiAubGA/3/screen.svg"
alt="" />
<p onClick={signIn}> 구글 아이디로 로그인 </p>
</div>
</div>
<div className="login_emailPass">
<div className="login_label">
<h4> 로그인 </h4>
</div>
<div className="login_inputFields">
<div className="login_inputField">
<input type="text" placeholder="이메일"
value={email} onChange={(e) => setEmail(e.target.value)} />
</div>
<div className="login_inputField">
<input type="password" placeholder="비밀번호" value={password} onChange={(e) => setPassword(e.target.value)} />
</div>
</div>
<div className="login_forgButt">
<small> 비밀번호 찾기</small>
<button type="submit" onClick={handleLogin}>로그인</button>
</div>
<button onClick={handleRegister}>회원가입</button>
</div>
</div>
</div>
</div>
);
}
export default Login;
컴포넌트를 꽤 많이 쪼갠것을 볼 수 있는데, 이것은 화면을 디자인할 때 조각이 많아야 더욱 디테일한
디자인이 가능하기 때문입니다, 위 코드를 보면 거의 버튼하나하나, input창 하나하나를 쪼갠걸 볼 수 있는데,
큰 덩어리부터 보게 되면 그다지 어려운 코드가 아닌걸 알 수 있습니다.
그리고 이 코드에서 동작을 수행하는것은 회원가입, 로그인, 구글 로그인정도이기 때문에
그것들에 대한 핸들러 함수를 상부에 작성하였습니다. 이 중에는 firebase 기본 메서드들 도 있습니다.
훑어보면서 공부하는것을 추천합니다.
Login.css 도 보겠습니다.
.login {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.login_container {
display: flex;
flex-direction: column;
padding: 20px;
width: 700px;
background-color: rgb(255, 255, 255);
border-radius: 10px;
}
.login_desc > p {
text-align: center;
font-weight: 500;
font-size: 20px;
}
.login_auth {
display: flex;
margin-top: 50px;
}
.login_authOptions {
display: flex;
flex: 0.5;
flex-direction: column;
padding: 20px;
border-right: 1px solid lightgray;
}
.login_authOption {
display: flex;
align-items: center;
padding: 7px;
margin-bottom: 15px;
border: 1px solid lightgray;
border-radius: 5px;
cursor: pointer;
}
.login_authOption:hover {
background-color: rgb(226, 226, 226);
}
.login_authOption > p {
margin-left: 11px;
}
.login_emailPass {
display: flex;
flex-direction: column;
justify-content: center;
padding: 20px;
flex: 0.5;
margin-left: 20px;
}
.login_inputFields {
display: flex;
flex-direction: column;
padding: 5px;
}
.login_inputField {
padding: 5px;
}
.login_forgButt {
padding-left: 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
.login_forgButt > button {
padding: 9px;
cursor: pointer;
}
.login_emailPass > button {
padding: 9px;
cursor: pointer;
margin-top: 10px;
}
크게 많은것을 구현하지 않을려고 했지만, 보기에는 좋아야 하니. 최소한의 css 를 구현했습니다.
이제 이렇게 작성한 후 출력되는 화면을 보겠습니다.
로그인 화면이 구현되었습니다. 구글로그인, 일반 로그인 두가지로 나뉘어졌습니다.
일단 먼저 구글 로그인을 해보겠습니다. 구글 아이디로 로그인 버튼 을 클릭합니다.
구글 계정을 선택하는 창이 뜹니다. 내 계정을 클릭해봅시다.
성공적으로 로그인 성공 창이 띄워졌습니다. 아래에 있는 로그아웃 버튼을 만들어야 합니다.
Main.js 로 갑니다.
해당 text 가 있는 하부에 버튼태그를 만들어 준 후
<button onClick={() => auth.signOut()}>Logout</button>
을 추가 해 줍니다. 그리고 상부에서 auth도 import 해줍니다. firebase.js 에서 가져오는겁니다.
signOut 메서드를 통해 인증을 해제시켜 user를 null 로 만들어 Login.js 로 보내는겁니다.
이렇게 버튼을 만들어 클릭을 하면 다시 로그인 창으로 돌아갑니다.
이번엔 이메일, 비밀번호로 들어가보겠습니다. 순서는 이러합니다.
이 순서대로 작성한 후 결과를 확인하자. 똑같은 결과가 나왔다. 두 방법 모두 성공했다.
firebase 로 간단한 백엔드를 구현해서 이메일, 구글로그인이 가능하게 구현해보았다.
리덕스로 사용자의 정보를 가져와서 로그인과 로그아웃의 기능이 가능하게 구현해보았다.