헤더 창에서 영화 검색하는 기능을 구현하고자 한다.
아이콘은 react-icons를 사용하고 스타일은 Emotion을 사용했다. 클릭여부를 props로 전달하여 인터랙티브하게 동작시켰다.
Emotion에서 props 전달 방법은 여기로 [emotion] props 전달 방법과 type 에러 해결방법
URL이 실시간으로 변하면서 검색결과를 불러오는 모습을 볼 수 있다!
// HeaderSearch.tsx
import { BsFillEraserFill, BsSearch } from "react-icons/bs"
import { useCallback, useEffect, useState } from "react"
import { SearchContainer } from "./HeaderSecondNav.style"
import { useRouter } from "next/router"
const HeaderSearch = () => {
const router = useRouter()
const [click, setClick] = useState(false)
const [search, setSearch] = useState('')
// 값이 변할때마다 새롭게 요청
useEffect(() => {
try {
if (search) {
router.replace({
pathname: '/search',
query: {
search: search,
page: 1
}
}, undefined, { shallow: true })
}
}
catch (e) {
console.error(e.response)
}
}, [search])
const clickSearchImg = () => setClick(!click)
const backPage = () => {
router.replace('/')
setSearch('')
setClick(false)
}
const handleSearchValue = useCallback((e) => {
setSearch(e.target.value)
}, [search])
return (
<SearchContainer click={click}>
<BsSearch onClick={clickSearchImg} size={30} />
<input type='text' placeholder='제목, 사람' autoFocus autoComplete='off' value={search} onChange={handleSearchValue} />
{search && <BsFillEraserFill onClick={backPage} size={30} />}
</SearchContainer>
)
}
export default HeaderSearch
// HeaderSearch.style.tsx
type SearchProps = {
click: boolean
}
export const SearchContainer = styled.div<SearchProps>`
display: flex;
align-items: center;
justify-content: center;
border-bottom: ${(props) => (props.click ? '1px solid red;' : 'none')};
background-color: ${(props) => (props.click ? 'black' : 'none')};
padding: 0.3rem;
margin-right: ${(props) => (props.click ? '1.25rem' : 0)};
> input {
transition: 0.3s width linear !important;
width: ${(props) => (props.click ? '12.5rem' : 0)};
background-color: ${(props) => (props.click ? 'black' : 'none')};
color: white;
border: none;
outline: none;
opacity: ${(props) => (props.click ? '1' : 0)};
margin-left: 0.625rem;
padding: 0.3rem;
}
`
// Search.tsx
import { SearchListTitle, SearchResultBox } from "./Search.style"
import { useEffect, useState } from "react"
import { IoIosArrowForward } from "react-icons/io"
import SearchResultActor from "./SearchResultActor"
import SearchResultGenre from "./SearchResultGenre"
import SearchResultMovie from "./SearchResultMovie"
import useGetActorSearch from "../../react-query/MovieData/ActorSearch"
import useGetMovieSearch from "../../react-query/MovieData/MovieSearch"
const SearchResult = (props) => {
// query값 받아오기
const { search, genreName } = props
// react-query를 이용하여 데이터를 불러옴
const actorSearch = useGetActorSearch(search).data
const movieSearch = useGetMovieSearch(search).data
const [movie, setMovie] = useState(true);
const [actor, setActor] = useState(true);
useEffect(() => { setMovie(true) }, [movieSearch])
useEffect(() => { setActor(true) }, [actorSearch])
return (
<>
{
genre && genreName ?
<SearchResultGenre genre={genre} genreName={genreName} /> :
<SearchResultBox>
<div>
<SearchListTitle movie={movie} actor={actor}>
<div>Movie {movieSearch?.pages[0]?.data?.total_results}<IoIosArrowForward onClick={() => setMovie(!movie)} size={35} /></div>
<div>Creator & Actor {actorSearch?.pages[0]?.data?.total_results} <IoIosArrowForward onClick={() => setActor(!actor)} size={35} /></div>
</SearchListTitle>
</div>
<SearchResultMovie search={search} click={movie} />
<SearchResultActor search={search} click={actor} />
</SearchResultBox>
}
</>
)
}
export default SearchResult