ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React - Search Container and Presenter
    Project using React/Cloning Netflix 2021. 5. 9. 11:07

    Search/SearchContainer.js

    import { moviesApi, tvApi } from "api";
    import React from "react";
    import SearchPresenter from "./SearchPresenter";
    
    export default class extends React.Component {
      state = {
        movieResults: null,
        tvResults: null,
        searchTerm: "",
        loading: false,
        error: null,
      };
    
      handleSubmit = (event) => {
        event.preventDefault();
        const { searchTerm } = this.state;
        if (searchTerm !== "") {
          this.searchByTerm();
        }
      };
    
      updateTerm = (event) => {
        const {
          target: { value },
        } = event;
        this.setState({
          searchTerm: value,
        });
      };
    
      searchByTerm = async () => {
        const { searchTerm } = this.state;
        this.setState({ loading: true });
        try {
          const {
            data: { results: movieResults },
          } = await moviesApi.search(searchTerm);
          const {
            data: { results: tvResults },
          } = await tvApi.search(searchTerm);
          this.setState({
            movieResults,
            tvResults,
          });
        } catch {
          this.setState({ error: "Can't find results." });
        } finally {
          this.setState({ loading: false });
        }
      };
    
      render() {
        const { movieResults, tvResults, searchTerm, loading, error } = this.state;
        return (
          <SearchPresenter
            movieResults={movieResults}
            tvResults={tvResults}
            loading={loading}
            error={error}
            searchTerm={searchTerm}
            handleSubmit={this.handleSubmit}
            updateTerm={this.updateTerm}
          />
        );
      }
    }
    

    updateTerm

      prop으로 넘겨준 state는 변경이 Read만 가능하다. 변경할 수 있는 방법은 this.setState를 이용한 방법 뿐이다. input에서 updateTerm으로 원하는 키워드를 쓴다.

    searchByTerm

      state에서 searchByTerm을 가져와서 movieResults와 tvResults 값을 가져온다.

    Search/Searchresenter.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: 20px;
    `;
    
    const Form = styled.form`
      margin-bottom: 50px;
    `;
    
    const Input = styled.input`
      all: unset;
      font-size: 20px;
      width: 100%;
    `;
    
    const SearchPresenter = ({
      movieResults,
      tvResults,
      loading,
      searchTerm,
      handleSubmit,
      updateTerm,
      error,
    }) => (
      <Container>
        <Helmet>
          <title>Search | Nomflix</title>
        </Helmet>
        <Form onSubmit={handleSubmit}>
          <Input
            placeholder="Search Movies or TV Shows..."
            value={searchTerm}
            onChange={updateTerm}
          />
        </Form>
        {loading ? (
          <Loader />
        ) : (
          <>
            {movieResults && movieResults.length > 0 && (
              <Section title="Movie Results">
                {movieResults.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>
            )}
            {tvResults && tvResults.length > 0 && (
              <Section title="TV Show Results">
                {tvResults.map((tv) => (
                  <Poster
                    key={tv.id}
                    id={tv.id}
                    imageUrl={tv.poster_path}
                    title={tv.original_name}
                    rating={tv.vote_average}
                    year={tv.first_air_date?.substring(0, 4)}
                  />
                ))}
              </Section>
            )}
          </>
        )}
      </Container>
    );
    
    SearchPresenter.propTypes = {
      movieResults: PropTypes.array,
      tvResults: PropTypes.array,
      error: PropTypes.string,
      searchTerm: PropTypes.string,
      loading: PropTypes.bool.isRequired,
      handleSubmit: PropTypes.func.isRequired,
      updateTerm: PropTypes.func.isRequired,
    };
    
    export default SearchPresenter;
    

    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는 필요가 없다.

    참고 자료

    소스 코드

    github.com/zpskek/Nomflix-v2/commit/6a98d6b6d1a1ea14b2618ea0d9e0ba2abb35fdfa

    댓글

Designed by Tistory.