ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React - Create MoviePresenter
    Project using React/Cloning Netflix 2021. 5. 9. 10:47

    Movie/MoviePresenter.js

    import Helmet from "react-helmet";
    import styled from "styled-components";
    import PropTypes from "prop-types";
    
    import Loader from "Components/Loader";
    import Poster from "Components/Poster";
    import Section from "Components/Section";
    
    const Container = styled.div`
      padding: 10px;
    `;
    
    const MoviePresenter = ({ nowPlaying, upcoming, popular, error, loading }) => (
      <>
        <Helmet>
          <title>Movies | Nomflix</title>
        </Helmet>
        {loading ? (
          <Loader />
        ) : (
          <Container>
            <Section title="Now Playing">
              {nowPlaying.map((movie) => (
                <Poster
                  key={movie.id}
                  id={movie.id}
                  imageUrl={movie.poster_path}
                  title={movie.original_title}
                  rating={movie.vote_average}
                  year={movie.release_date.substring(0, 4)}
                  isMovie={true}
                />
              ))}
            </Section>
            <Section title="Upcoming">
              {upcoming.map((movie) => (
                <Poster
                  key={movie.id}
                  id={movie.id}
                  imageUrl={movie.poster_path}
                  title={movie.original_title}
                  rating={movie.vote_average}
                  year={movie.release_date.substring(0, 4)}
                  isMovie={true}
                />
              ))}
            </Section>
            <Section title="Popular">
              {popular.map((movie) => (
                <Poster
                  key={movie.id}
                  id={movie.id}
                  imageUrl={movie.poster_path}
                  title={movie.original_title}
                  rating={movie.vote_average}
                  year={movie.release_date.substring(0, 4)}
                  isMovie={true}
                />
              ))}
            </Section>
          </Container>
        )}
      </>
    );
    
    MoviePresenter.propTypes = {
      nowPlaying: PropTypes.array,
      popular: PropTypes.array,
      upcoming: PropTypes.array,
      loading: PropTypes.bool.isRequired,
      error: PropTypes.string,
    };
    
    export default MoviePresenter;
    

    key

      nowPlaying, upcoming, popular는 모두 배열이다. 이들을 map을 이용해서 <Poster>를 부르고 있다. 이 때 리스트 안에 있는 <Poster>에 key 값을 추가해야만 한다.

    prop-types

    설치

    $ npm i prop-types

    개요

      prop-types는 prop의 type을 정의한다. prop을 받을 component 뒤에 method 형식으로 propTypes를 하고 객체를 정의한다.

      위 코드와 같이 type을 정의하면 MoviePresenter가 받아들이는 prop이 옳지 않은 type일 때 error를 일으켜 개발자가 실수 하는 것을 막아준다. 만약 React를 typescript로 짰다면 prop-types는 필요가 없다.

    Components/Section.js

    import PropTypes from "prop-types";
    import styled from "styled-components";
    
    const Container = styled.section`
      :not(:last-child) {
        margin-bottom: 50px;
      }
    `;
    
    const Title = styled.h2`
      font-size: 14px;
      font-weight: 600;
    `;
    
    const Grid = styled.div`
      margin-top: 25px;
      display: grid;
      grid-template-columns: repeat(auto-fill, 125px);
      grid-gap: 25px;
    `;
    
    const Section = ({ title, children }) => (
      <Container>
        <Title>{title}</Title>
        <Grid>{children}</Grid>
      </Container>
    );
    
    Section.propTypes = {
      title: PropTypes.string.isRequired,
      children: PropTypes.oneOfType([
        PropTypes.arrayOf(PropTypes.node),
        PropTypes.node,
      ]),
    };
    
    export default Section;

    children

      MoviePresenter가 <Section>에게 준 prop은 title 뿐이다. 하지만 Section에는 children이 정의되어 있다. children은 open component tag와 close component tag 사이에 있는 아이다. MoviePresenter를 보면 <Section></Section> 사이에 <Poster> list가 있다. 이것이 Section에게 children이라는 특별한 prop으로 전달된다.

    Components/Poster.js

    import styled from "styled-components";
    import PropTypes from "prop-types";
    
    const Container = styled.div``;
    
    const Image = styled.div`
      background-image: url(${(props) => props.bgUrl});
      width: 100%;
      height: 180px;
      background-repeat: no-repeat;
      background-size: cover;
      background-position: center;
      transition: opacity 0.1s linear;
    `;
    
    const Rating = styled.span`
      bottom: 5px;
      right: 5px;
      position: absolute;
      opacity: 0;
      transition: opacity 0.1s linear;
    `;
    
    const ImageContainer = styled.div`
      position: relative;
      &:hover {
        ${Image} {
          opacity: 0.3;
        }
        ${Rating} {
          opacity: 1;
        }
      }
    `;
    
    const Title = styled.span`
      display: block;
      margin-bottom: 3px;
    `;
    
    const Year = styled.span`
      font-size: 10px;
      color: rgba(255, 255, 255, 0.5);
    `;
    
    const Poster = ({ id, imageUrl, title, rating, year }) => (
      <Container>
        <ImageContainer>
          <Image
            bgUrl={
              imageUrl
                ? `https://image.tmdb.org/t/p/w300${imageUrl}`
                : require("../assets/noPosterSmall.png")
            }
          />
          <Rating>
            <span role="img" aria-label="rating">
              ⭐️
            </span>{" "}
            {rating}/10
          </Rating>
        </ImageContainer>
        <Title>{title.length > 18 ? `${title.substring(0, 18)}...` : title}</Title>
        <Year>{year}</Year>
      </Container>
    );
    
    Poster.propTypes = {
      id: PropTypes.number.isRequired,
      imageUrl: PropTypes.string,
      title: PropTypes.string.isRequired,
      rating: PropTypes.number,
      year: PropTypes.string,
      isMovie: PropTypes.bool,
    };
    
    export default Poster;

    참고 자료

    소스 코드

    github.com/zpskek/Nomflix-v2/commit/dc55c54f3061bfabf05b2bf2949db4064551612b

    'Project using React > Cloning Netflix' 카테고리의 다른 글

    React - Search Container and Presenter  (0) 2021.05.09
    React - Create TV Container and Presenter  (0) 2021.05.09
    React - Create Loader.js  (0) 2021.05.09
    React - Create MovieContainer  (0) 2021.05.09
    React Life cycle Methods  (0) 2021.05.09

    댓글

Designed by Tistory.