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의 문법에 따라 빈 태그 <></>로 한번 더 감싸주면 해결.

좋은 웹페이지 즐겨찾기