목표 - 회원가입 후 파이어베이스에 즉시 로그인한 다음 브라우저의 indexDB에 저장된 데이터를 Twitter 에 반영해보자 |
** 로그인 처리 후 currentUser가 null인 이유? **
비동기 처리 과정을 이해해야 함
1) 컴퓨터와 firebase 서버 사이의 거리는 엄청 멀다
2) 이 때문에 파이어베이스에서 로그인 처리를 마치고 트위터에서 그 신호를 받기까지는 시간 간격이 생김
3) 그 사이에 트위터가 currentUser 값을 확인하게 됨
4) null
====>> 리액트의 생명주기 이용
액션1 - 딜레이 눈으로 확인해 보기
setInterval 함수를 사용, 2초마다 실행
회원가입 후 로그인 처리 완료까지 얼마나 시간이 걸리는지 살펴본다.
import { useState } from "react";
import AppRouter from "components/Router";
import { authService } from "fbase";
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(authService.currentUser);
setInterval(() => console.log(authService.currentUser), 2000);
return (
<>
<AppRouter isLoggedIn={isLoggedIn} />
<footer>© {new Date().getFullYear()} Twitter</footer>
</>
);
}
export default App;
null 에서 Im 으로 바뀌었다
currentUser가 변경되는 시점을 알기 위해 useEffect함수 사용
액션2 - useEffect 함수 사용하기
useEffect 함수는 특정한 시점에 실행되는 함수.
우리가 원하는 특정 시점 -> 파이어베이스 로그인 정보를 받게 되었을 때(파이어베이스가 초기화 되는 시점)
이 시점을 useEffect 함수로 잡아낸 다음 이때 로그인 완료 후 보여줄 화면을 렌더링
authService에 포함된 함수 중 onAuthStateChanged 는 인증 관련 상태가 바뀌는 것을 감지하는 함수
import { useEffect, useState } 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(user);
} else {
setIsLoggedIn(false);
}
setInit(true);
});
}, []);
return (
<>
{init ? <AppRouter isLoggedIn={isLoggedIn} /> : "initializing..."}
<footer>© {new Date().getFullYear()} Twitter</footer>
</>
);
}
export default App;
authService.currentUser 함수는 처음에 null을 반환 하므로 isLoggedIn 은 null로 시작할 가능성이 높음,
불확실성을 제거하기 위해 isLoggedIn을 user로 설정 -> 이렇게 해야 isLoggedIn를 AppRouter 컴포넌트 프롭스에 제대로 보낼 수 있음
액션3 - 로그아웃은 어떻게?
indexedDB 를 clear한다. (아직은 수동인 상태!!)
그전에 에러메세지 적용!!
액션4 - 에러와 에러 메시지를 파이어베이스로 처리하기
const Auth = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [newAccount, setNewAccount] = useState(true);
const [error, setError] = useState("");
이제 에러가 발생할 지점에 setError를 사용하면 됨
error에 어떤 메세지를 담을지 정해야 함.
액션5 - 일부러 중복 회원가입 에러 발생시켜 보기
지금은 그냥 error를 출력하고 있어서 우리가 원하는 메시지가 x
액션6 - error.message 화면에 출력하기
에러가 발생하면 setError 함수에 error.message를 전달해서 error상태를 변화시키자!
그럼 에러가 발생할 때 화면에 error.message가 출력
import { authService } from "fbase";
import { 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) => {
event.preventDefault();
try {
let data;
if (newAccount) {
data = await authService.createUserWithEmailAndPassword(
email,
password
);
//create newAccount
} else {
data = await authService.signInWithEmailAndPassword(email, password);
//log in
}
console.log(data);
} catch (error) {
setError(error.message);
}
};
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"} />
{error}
</form>
<div>
<button>Continue with Google</button>
<button>Continue with Github</button>
</div>
</div>
);
};
export default Auth;
catch(error)에 setError(error.message); 를 넣어주고
submit 아래 {error} 를 추가하였다.
중복 로그인 시 오류 메세지가 뜬다.
액션7 - 조금 더 섬세하게! 로그인, 회원가입 토글 버튼 적용
로그인, 회원가입 토글 버튼을 적용해보자.
로그인 여부에 따라 로그인, 회원가입이 전환되도록! -> 이렇게 하면 로그인, 회원가입에 맞춰 화면을 준비할 필요가 x
import { authService } from "fbase";
import { 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) => {
event.preventDefault();
try {
let data;
if (newAccount) {
data = await authService.createUserWithEmailAndPassword(
email,
password
);
//create newAccount
} else {
data = await authService.signInWithEmailAndPassword(email, password);
//log in
}
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" : "Log 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;
모든 UseState 함수들은 바로 이전 상태를 참조 할 수 있음!!
ex))
setNewAccount((prev) => !prev) 와 같이 작성 -> setNewAccount 함수에 (prev) => !(prev) 와 같이 함수를 전달한것
이렇게 UseState 함수에 함수를 인자로 전달하면 인자로 전달한 첫번째 인자 이전의 상태가 넘어옴
'리액트 - 클론코딩' 카테고리의 다른 글
트위터 클론코딩 - 트위터에 소셜 로그인 추가하기 (0) | 2023.05.14 |
---|---|
트위터 클론코딩 - 이메일, 비밀번호 인증 기능 사용해보기 (0) | 2023.05.11 |
트위터 클론코딩 - 파이어베이스 로그인 설정하기 (0) | 2023.05.11 |
트위터 클론코딩 - 파이어베이스 로그인 준비하기 (1) | 2023.05.10 |
트위터 클론코딩 - 라우터 적용하기(isLoggedIn을 사용한 삼항연산자) (0) | 2023.05.10 |