Disney+ 사이트 클론 - 8
movieSlice와 동일하게 user폴더에 userSlice를 만들고
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
name: "",
email: "",
photo: "",
};
const userSlice = createSlice({
name: "user",
initialState,
reducers: {
setuserLogin: (state, action) => {
state.name = action.payload.name;
state.email = action.payload.email;
state.photo = action.payload.photo;
},
setSignOut: (state) => {
state.name = null;
state.email = null;
state.photo = null;
},
},
});
export const { setUserLogin, setSignOut } = userSlice.actions;
export const selectUserName = (state) => state.user.name;
export const selectUserEmail = (state) => state.user.email;
export const selectUserPhoto = (state) => state.user.photo;
export default userSlice.reducer;
초기설정을 해준다. 이 코드는 유저가 로그인하면 로그인 한 값으로 설정해주고 로그아웃 하면 그 값들을 다시 null로 바꿔준다.
store.js에서 동일하게 import해주고 reducer에 추가해준다.
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "../features/user/userSlice"
import movieReducer from "../features/movie/movieSlice";
export const store = configureStore({
reducer: {
movie: movieReducer,
user: userReducer
},
});
이제 로그인 한 상태가 아니면 Header의 메뉴들 대신 Login버튼만 보여줄 것이기 때문에 Header.js로 가서
import { selectUserName, selectUserPhoto } from "../features/user/userSlice.js";
import { useSelector } from "react-redux";
function Header() {
const userName = useSelector(selectUserName);
const userPhoto = useSelector(selectUserPhoto);
만들어준것들과 셀렉터를 import하고 불러와준다.
그리고 Nav메뉴는 유저가 로그인 한 상태에만 보여줄 것이기 때문에 !userName으로 userName이 존재하지 않으면 Login만 아니면 NavMenu를 보여주도록 한다.
return (
<Nav>
<Logo src="/images/logo.svg" />
{!userName ? (
<Login>Login</Login>
) : (
<>
<NavMenu>
<a>
<img src="/images/home-icon.svg" />
<span>HOME</span>
</a>
<a>
<img src="/images/search-icon.svg" />
<span>SEARCH</span>
</a>
<a>
<img src="/images/watchlist-icon.svg" />
<span>WATCHLIST</span>
</a>
<a>
<img src="/images/original-icon.svg" />
<span>ORIGINALS</span>
</a>
<a>
<img src="/images/movie-icon.svg" />
<span>MOVIES</span>
</a>
<a>
<img src="/images/series-icon.svg" />
<span>SERIES</span>
</a>
</NavMenu>
<UserImg src="https://pbs.twimg.com/profile_images/601738800310583296/mBwRWaKY_400x400.png" />
</>
)}
</Nav>
);
스타일을 지정해줘서 위치와 모양을 바꾸면
...
<LoginContainer>
<Login>Login</Login>
</LoginContainer>
...
const Login = styled.div`
border: 1px solid #f9f9f9;
border-radius: 4px;
padding: 8px 16px;
letter-spacing: 1.5px;
text-transform: uppercase;
background-color: rgba(0, 0, 0, 0.6);
transition: all 0.2s ease 0s;
cursor: pointer;
&:hover {
background-color: #f9f9f9;
color: #000;
border-color: transparent;
}
`;
const LoginContainer = styled.div`
flex: 1;
display: flex;
justify-content: flex-end;
`;
이제 firebase.js에 설정한 GoogleAuthProvider를 적용하자
function Header() {
...
const signIn = () => {
auth.signInWithPopup(provider).then((result) => {
console.log(result);
});
};
...
return (
<Nav>
<Logo src="/images/logo.svg" />
{!userName ? (
<LoginContainer>
<Login onClick={signIn}>Login</Login>
</LoginContainer>
signIn함수를 만들고 Login태그에 onClick으로 지정해주면
Login을 클릭했을 때 아래와 같은 구글 로그인 창이 나타난다.
로그인해서 clg로 찍어본 정보를 보면
우리가 필요한 displayName, email, photoURL의 정보를 볼 수 있다.
이 데이터들을 받아오기 위해 setUserLogin과 useDispatch를 import하고 dispatch를 활용해 데이터를 받아보자
import {
selectUserName,
selectUserPhoto,
setUserLogin,
} from "../features/user/userSlice.js";
import { useDispatch, useSelector } from "react-redux";
function Header() {
const dispatch = useDispatch();
const userName = useSelector(selectUserName);
const userPhoto = useSelector(selectUserPhoto);
const signIn = () => {
auth.signInWithPopup(provider).then((result) => {
let user = result.user;
dispatch(
setUserLogin({
name: user.displayName,
email: user.email,
photo: user.photoURL,
})
);
console.log(result);
});
};
우리가 필요한 데이터는 user안에 있으므로 provieder로부터 result를 받아오고 result.user를 변수로 지정한 뒤 이를 dispatch하여 필요한 데이터를 setUserLogin에 할당해준다.
이렇게 되면 로그인을 했을 때 setUserLogin의 GlobalState가 업데이트 되어 userName도 유효한 값을 가지게 되어 Login버튼 대신 NavMenu들이 보이게 된다.
이제 프로필 아이콘을 클릭하면 로그아웃 하는 기능을 만들자 로그인과 동일하게
const signOut = () => {
auth.signOut().then(() => {
dispatch(setSignOut());
navigate("/login");
});
};
...
</a>
</NavMenu>
<UserImg
onClick={signOut}
src={userPhoto}
/>
setSignOut을 실행함과 동시에 로그인 페이지로 이동시켜주는 함수를 만들어주고 UserImg에 onClick이벤트로 등록해준 뒤 이미지 경로를 userPhoto로 바꿔준다.
프로필이미지를 클릭하면 로그아웃 됨과 동시에 로그인 페이지로 이동한다.
추가로 로그인 했을 때에도 홈페이지로 이동하도록 signIn함수 안에 navigate를 추가하자
name: user.displayName,
email: user.email,
photo: user.photoURL,
})
);
navigate("/");
console.log(result);
});
};
그런데 로그인 한 상태에서 새로고침을 하면 로그인 상태가 풀리는 현상이 있다.
useEffect(() => {
auth.onAuthStateChanged(async (user) => {
if (user) {
dispatch(
setUserLogin({
name: user.displayName,
email: user.email,
photo: user.photoURL,
})
);
navigate("/");
}
});
}, []);
useEffect를 추가해서 새로고침해서 화면을 다시 렌더링해도 로그인상태로 진입하도록 해주자
Author And Source
이 문제에 관하여(Disney+ 사이트 클론 - 8), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@fantazindy/Disney-사이트-클론-8저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)