MovieApp 만들기 (검색 페이지)

김재훈·2023년 9월 17일

MovieApp 만들기

목록 보기
4/8

검색 페이지

검색창

form 태그와 useState를 사용해 입력을 받아서 검색어를 검색페이지로 useNavigate()를 사용해 검색 페이지로 보낸다. 그리고 반응형으로 브라우저 크기에 맞게 검색창 크기를 조절한다.

// src/Search/components/SearchBar.tsx

import { useState } from "react";
import { useNavigate } from "react-router-dom";

const SearchBar = (props: Props) => {
  const navigate = useNavigate();
  const [searchWord, setSearchWord] = useState<string>("");

  const handleSearchSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    navigate(`/search/${searchWord}`);
    setSearchWord("");
  };

  const handleChange = ({ target }: React.ChangeEvent<HTMLInputElement>) => {
    const word = target.value;
    setSearchWord(word);
  };

  return (
    <form onSubmit={handleSearchSubmit}>
      <SearchInput
        value={searchWord ?? ""}
        type="text"
        onChange={handleChange}
      />
      <SearchButton>검색</SearchButton>
    </form>
  );
};

export default SearchBar;

const SearchInput = styled.input`
  border-radius: 40px;
  margin-right: 1rem;
  color: black;
  padding: 5px;

  @media screen and (max-width: 1023px) {
    width: 100px;
  }

  @media screen and (max-width: 767px) {
    width: 100px;
  }
`;

const SearchButton = styled.button`
  width: 50px;
  height: 30px;

  @media screen and (max-width: 1023px) {
    width: 40px;
    font-size: 5px;
  }

  @media screen and (max-width: 767px) {
    width: 50px;
    height: 30px;
  }
`;

검색 페이지

다른 영화 목록 페이지처럼 useInfiniteQueryInfiniteScroll를 사용해 무한 스크롤 페이지로 구성한다. 그리고 영화 상세 페이지에서처럼 useParams()를 사용해서 파라미터값을 가져온다.

// src/pages/Search/SearchMoviePage.tsx

const SearchMoviePage = (props: Props) => {
  const { searchWord } = useParams() as { searchWord: string };

  const { isLoading, isError, data, fetchNextPage, hasNextPage } =
    useInfiniteQuery(
      ["search", searchWord],
      ({ pageParam = 1 }) => getSearchMovie(searchWord, pageParam),
      {
        getNextPageParam: (lastPage) => {
          let page = lastPage.page;
          if (lastPage.total_page === page) {
            return false;
          }
          return page + 1;
        },
      }
    );

  if (isLoading) <h1>Loading...</h1>;
  if (isError) <h1>Error ㅠㅠ</h1>;

  return (
    <InfiniteScroll loadMore={() => fetchNextPage} hasMore={hasNextPage}>
      <MovieList>
        {data?.pages?.map((page) => {
          return page?.results.map((movie: MovieDetail) => (
            <Fragment key={movie.id}>
              <MovieCard movieData={movie} />
            </Fragment>
          ));
        })}
      </MovieList>
    </InfiniteScroll>
  );
};

export default SearchMoviePage;

스크롤업 버튼

window.scrollY를 이용해 스크롤이 1000px 넘게 스크롤 됐을 경우 useState를 사용해 isScrolltrue로 변경해 스크롤업 버튼이 보이게 한다.

스크롤업 버튼을 누르면 window.scrollTo를 사용해 제일 위로 스크롤을 이동시킨다.

그리고 스크롤업 버튼의 z-index 값을 줘서 목록의 MovieCard와 겹칠경우 위쪽에 위치하게 한다.

// src/components/ScrollUpButton.tsx

import React, { useEffect, useState } from "react";

import styled from "styled-components";

type Props = {};

const ScrollUpButton = (props: Props) => {
  const [isScroll, setIsScroll] = useState<boolean>(false);

  const handleScroll = () => {
    const { scrollY } = window;

    scrollY > 1000 ? setIsScroll(true) : setIsScroll(false);
  };

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);

    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

  const scrollToTop = () => {
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  return isScroll ? (
    <ScrollUpWrapper>
      <button onClick={scrollToTop}>TOP</button>
    </ScrollUpWrapper>
  ) : (
    <></>
  );
};

export default ScrollUpButton;

const ScrollUpWrapper = styled.div`
  position: fixed;
  right: 5%;
  bottom: 5%;
  z-index: 1;

  button {
    font-weight: bold;
    font-size: 15px;
    padding: 10px 10px;
    border: 1px solid white;
    border-radius: 35%;
    background-color: #000;
    color: #fff;
    outline: none;
    cursor: pointer;
  }
`;
profile
김재훈

0개의 댓글