# App.js
index.js를 제외하면 최상위 컴포넌트 파일이다.
App.js에서부터 속성들을 가져와야 한다.
필요한 속성은 userObj이다.
userObj는 파이어베이스에서 getFirestore.currentUser.[ 필요한키 ]
이렇게 가져올 수 있는 데이터이지만 userObj라는 변수를 만들어 속성에 넣고
여기저기서 전달받아 사용하는 이유는 소스를 통합하여 확장성 있게
사용하고 싶기때문이다. userObj 하나만 변경해도 통합되어 변경되기 때문에
더 직관적으로 변경,저장하기 쉬워진다.
function App() {
const [init, setInit] = useState(false); //false = 홈화면대기중...
const [userObj, setUserObj] = useState(null); //유저데이터를 위한 스테이트
useEffect(()=>{
authService.onAuthStateChanged((user)=>{
//firestore에서 auth 변화리스너, 고로 user = usedata이다.
if (user) {
setIsloggedIn(true);
setUserObj({
displayName: user.displayName,
uid: user.uid,
updateProfile: { displayName: user.displayName },
/* user에는 아주 많은 유저데이터가 있는데 그 중 필요한 key만 가져와서
값을 적용시켜주고 있다. 방대한 데이터는 re-render에 불리하기때문이다. */
});
} else {
setIsloggedIn(false); //flase = 로그인실패.
}
setInit(true); //true = 홈화면이 된다.
});
},[]);
const refreshUser = () => {
const user = authService.currentUser;
//refreshUser에는 user가 존재하지 않아, 새로 선언해준다.
setUserObj({
displayName: user.displayName,
uid: user.uid,
updateProfile: { displayName: user.displayName },
});
}
//refreshUser함수를 만든 이유는 프로필 업데이트 기능을 위해서다.
return (
<>
{ init ? (
<AppRouter
isLoggedIn={isLoggedIn}
userObj={userObj}
refreshUser={refreshUser}
/>
) : (
"Initializing...."
) }
</>
);
//AppRouter에 속성들을 전달시켜준다.
}
# Router.js
두번째 컴포넌트파일이며, Profile 컴포넌트로 속성들을 전달해준다.
import {
BrowserRouter as Router, Route, Routes,
} from "react-router-dom";
import {Auth} from "routes/Auth";
import {Home} from "routes/Home";
import {Profile} from "routes/Profile";
import {Navigation} from "components/Navigation";
export const AppRouter = ( {refreshUser, isLoggedIn, userObj} )=> {
return (
<Router>
{isLoggedIn && <Navigation userObj={userObj}/>}
<Routes>
{isLoggedIn ? (
<>
<Route path="/" element={<Home userObj={userObj}/>}/>
<Route path="/Profile"
element={ <Profile userObj={userObj}
refreshUser={refreshUser} /> }
/>
</>
): (
<>
<Route path="/" element={<Auth/>}/>
</>
)}
</Routes>
</Router>
);
};
AppRouter 인자로 오브젝트 리터럴로 속성이름을 넣어서 전달받고
컴포넌트요소 안에도 동일명속성으로 중괄호 안도 넣어준다.
# Navigation.js
고정 되어있는 네비게이션 컴포넌트파일이다.
import React from "react";
import {Link} from "react-router-dom";
export const Navigation = ({ userObj })=> {
return (
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/profile">{userObj.displayName}의 Profile</Link>
</li>
</ul>
</nav>
);
};
Home 메뉴와 userObj.displayName + "의 Profile" 메뉴가 있다.
userObj.displayName는 현재 접속되어있는 유저데이터에서 이름을 가져온다.
# Profile.js
import React, {useEffect, useState} from "react";
import {authService, dbService} from "Fbase";
import { useNavigate } from "react-router-dom";
import {collection, getDocs, query, where} from "@firebase/firestore";
import {updateProfile} from "@firebase/auth";
export const Profile = ( { refreshUser, userObj } )=> {
//상위 컴포넌트에서 가져온 속성들
const navigate = useNavigate();
//로그아웃 처리 후 홈화면으로 이동시킬때 사용
const [newDisplayName, setNewDisplayName] = useState(userObj.displayName);
//가져온 유저데이터에서 displayName
const onLogOutClick = () => {
authService.signOut();
navigate("/",{replace:true});
};
// eslint-disable-next-line react-hooks/exhaustive-deps
const getMyZweets = async ()=> {
try {
const q = query(
collection(dbService,"zweets"),
where("creatorId", "==", userObj.uid),
);
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc)=>{
console.log(doc.id,"=>",doc.data());
});
} catch (e) {
console.log(e);
}
}
useEffect(()=> {
getMyZweets();
},[getMyZweets])
const onChange = ( {target: {value} }) => {
setNewDisplayName(value);
}
const onSubmit = async (e)=> {
e.preventDefault();
if(userObj.displayName !== newDisplayName){
await updateProfile(authService.currentUser,{displayName: newDisplayName});
/*여기서 userObj가 아닌 authService.currentUser를 사용한 이유는
파이어베이스 v9부터는 메소드의 영역이 다르기 때문에 위와같이 해결했다. */
}
refreshUser();
//서브밋되면 리프레쉬유저함수를 실행시켜 프로필도 re-render되게 만든다.
}
return (
<>
<form onSubmit={onSubmit}>
<input
onChange={onChange}
type="text"
placeholder="Display name"
value={newDisplayName}
/>
<input type="submit" value="Update Profile"/>
</form>
<button onClick={onLogOutClick}>Log Out</button>
</>
)
};
프로필 화면에서 텍스트인풋내에 글을 쓴 후 Update Profile 버튼이나
엔터를 눌러 서브밋하면 refreshUser함수가 실행되어 네비게이션의 프로필이름이 바뀐다.
# refreshUser 함수 다시보기
const refreshUser = () => {
const user = authService.currentUser;
setUserObj({
displayName: user.displayName,
uid: user.uid,
updateProfile: { displayName: user.displayName },
});
}
setUserObj로 인하여 userObj가 변경되고
변화를 감지한 react가 re-render시킨 것이다.