Disney+ 사이트 클론 - 7
이제 심슨으로만 고정되어 있는 Movie들을 DB에 있는 리스트들을 가져와서 적용시켜보자.
firebase DB를 이용할 예정이다.
firebase.js를 만들고
import firebase from "firebase";
const firebaseConfig = {
apiKey: "AIzaSyCEFYT7dUHrDBbIyPxmqezYzzlhV49WokA",
authDomain: "disney-plus-cbe56.firebaseapp.com",
projectId: "disney-plus-cbe56",
storageBucket: "disney-plus-cbe56.appspot.com",
messagingSenderId: "640166483034",
appId: "1:640166483034:web:f6bb33f81635bcecb1f463",
measurementId: "G-WXFXQYQY2H",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
const db = firebaseApp.firestore();
const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
const storage = firebase.storage();
export { auth, provider, storage };
export default db;
사용할 DB의 정보와 설정을 입력한다.
이후 movieSlice.js를 만들고
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
movies: [],
};
const movieSlice = createSlice({
name: "movie",
initialState,
reducers: {
setMovies: (state, action) => {
state.movies = action.payload;
},
},
});
export const { setMovies } = movieSlice.actions;
export const selectMovies = (state) => state.movie.movies;
export default movieSlice.reducer;
redux를 사용해 초기설정을 해준뒤 store.js로 가서
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
import movieReducer from "../features/movie/movieSlice";
export const store = configureStore({
reducer: {
movie: movieReducer,
},
});
기존의 reducer를 방금 만든 movieSlice를 통한 Reducer로 바꿔준다.
그리고 가장 중요한 작업으로 Home.js로 돌아와 db정보를 useEffcet와 map메소드를 통해 나열해주고
...
function Home() {
const dispatch = useDispatch();
useEffect(() => {
db.collection("movies").onSnapshot((snapshot) => {
let tempMovies = snapshot.docs.map((doc) => {
return { id: doc.id, ...doc.data() };
});
console.log(tempMovies);
dispatch(setMovies(tempMovies));
});
}, []);
return (
<Container>
...
Movie.js로 가서 movies라는 변수에 Selector를 넣어주고 map메소드로 각각 화면에 그려주고 Link to를 활용해 해당 movie를 클릭하면 해당 movie의 id값을 가진 주소로 이동하게 해주었다.
function Movies() {
const movies = useSelector(selectMovies);
console.log("This is movies", movies);
return (
<Container>
<h4>Recommended for You</h4>
<Content>
{movies &&
movies.map((movie) => (
<Wrap key={movie.id}>
<Link to={`/detail/${movie.id}`}>
<img src={movie.cardImg} />
</Link>
</Wrap>
))}
</Content>
...
그리고 App.js에서 detail페이지에 해당하는 path를 수정해주자
...
<Header />
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/detail/:id" element={<Detail />} />
<Route path="/" element={<Home />} />
</Routes>
</Router>
...
DB에 있는 데이터들을 잘 불러와서 보여주고 있고 아무 movie나 눌러보면
해당 id의 주소로 잘 이동한다.
이미지와 설명이 그대로인 이유는 아직 detail 페이지는 static상태이기 때문이다.
이제 detail 페이지도 동적 페이지로 바꿔보자.
Detail.js에서 db와 useParams를 import하고
import styled from "styled-components";
import { useParams } from "react-router-dom";
import db from "../firebase";
function Detail() {
const { id } = useParams();
console.log(id);
useParams로 movie의 id를 가져오자
clg로 확인해본 결고 잘 가져와졌다.
이제 useEffect와 useState를 import하고 이를 활용해보자
...
console.log(id);
const [movie, setMovie] = useState();
useEffect(() => {
db.collection("movies")
.doc(id)
.get()
.then((doc) => {
if (doc.exists) {
setMovie(doc.data());
} else {
}
});
}, []);
console.log("Movie is", movie);
useState로 movie와 setMovie를 만들어주고 useEffect로 db에 id를 통해 접근하고 데이터를 받아와 데이터가 있으면 setMoive를 통해 받아온 데이터를 moive에 지정해주었다.
clg로 확인해보면
원하는 데이터를 객체형태로 잘 받아왔다.
이제 이 받아온 데이터를 static값에 넣어주면 완성이다.
시험삼아 하나만 바꿔보자
return (
<Container>
<Background>
<img src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img src="https://www.seekpng.com/png/full/20-200510_frozen-musical-logo-frozen-logo-png.png" />
</ImageTitle>
기존의 static한 url주소를 movie.backgroundImg로 바꿔주었다.
이미지가 잘 바뀌었다. 이제 나머지도 바꿔주자.
잘 나오는듯 싶지만 홈페이지에서 다시 detail페이지로 들어가고자 하면
이와 같은 에러를 띄운다.
위쪽을 잘 보면 Movie is 'undefined'라고 하는데 useEffcet에서 처음데 데이터를 그려주려고 할 때 DB에서 아직 데이터를 불러오지 못하였기 때문에 movie의 값이 없기 때문이다.
이를 해결하기 위해서는 movie.xxx의 값들을 사용 할 때 movie.의 값이 존재할때만 사용하도록 해주면 된다.
detail.js의 return을
return (
<Container>
{movie && (
<>
<Background>
<img src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img src={movie.titleImg} />
</ImageTitle>
<Controls>
<PlayButton>
<img src="/images/play-icon-black.png" />
<span>PLAY</span>
</PlayButton>
<TrailerButton>
<img src="/images/play-icon-white.png" />
<span>Trailer</span>
</TrailerButton>
<AddButton>
<span>+</span>
</AddButton>
<GroupWatchButton>
<img src="/images/group-icon.png" />
</GroupWatchButton>
</Controls>
<SubTitle>{movie.subTitle}</SubTitle>
<Description>{movie.description}</Description>
</>
)}
</Container>
);
{movie && (...)}로 감싸주면 된다. 그리고 styled-component의 문법에 따라 빈 태그 <></>로 한번 더 감싸주면 해결.
Author And Source
이 문제에 관하여(Disney+ 사이트 클론 - 7), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@fantazindy/Disney-사이트-클론-7-05ajth6i저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)