커뮤니티 내에서 글을 검색하는 기능을 만들고자 한다.
돋보기 아이콘은 react-icons를 사용했다. 아이콘이 필요할 때 제일 사용하기 간편한 것 같다.
모달창에는 검색 조건을 선택할 수 있고 검색 내용을 적는 곳이 있다. 그리고 뒤로가기와 검색 버튼이 있다.
모달창은 내가 직접 만들었다. 어렵지 않게 직접 만들 수 있다.
모달 구현이 궁금하다면 [Next.js] 모달창 정말 쉽게 구현하기
내가 필요한 것은 검색 조건을 선택하는 것이니 Material UI에 들어가서 Select에 관한 UI를 보고 내가 사용할 UI를 선택했다.
Material UI - select
나는 small size의 select를 선택했다.
아래와 같이 구현 코드가 적혀있기 때문에 필요한 라이브러리를 다운받고 내 프로젝트에 잘 적용만 시키면 된다.
검색 조건과 검색 내용을 검색결과 페이지 url의 path와 query에 담아 보낸다.
이전에는 router.push를 작성할 때 path에만 조건을 적어봤는데, 이번에는 path와 query를 모두 담아내는 상황이다.
그럴 때는 아래와 같이 중괄호를 열고 pathname과 query를 따로 적어줘야 한다.
router.push({
pathname: `/community/feed/search/${type}`,
query: {
search: search,
page: 1,
},
})
// FeedSearchMoadl.tsx
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import FormControl from '@mui/material/FormControl'
import Select, { SelectChangeEvent } from '@mui/material/Select'
import { useState } from 'react'
import { SearchModalBox } from './FeedSearchModal.style'
import { toast } from 'react-toastify'
import router from 'next/router'
const FeedSearchModal = (props) => {
const { clickModal } = props
// 검색 내용
const [search, setSearch] = useState('')
const handleChange = (e) => setSearch(e.target.value)
// 검색 조건
const [type, setType] = useState('')
const typeChange = (e: SelectChangeEvent) => setType(e.target.value)
const clickSearch = async () => {
// 검색 내용과 조건이 설정되어 있을 경우에만 검색
if (type && search) {
try {
clickModal()
router.push({
pathname: `/community/feed/search/${type}`,
query: {
search: search,
page: 1,
},
})
} catch (e) {
console.error(e.response)
}
} else if (!type) toast.error('검색 조건 설정해주세요')
else toast.error('검색어 입력해주세요')
}
return (
<SearchModalBox onClick={clickModal}>
<div onClick={(e) => e.stopPropagation()}>
<FormControl size='small'>
<InputLabel id='demo-select-small'>검색</InputLabel>
<Select labelId='demo-select-small' id='demo-select-small' value={type} label='type' onChange={typeChange}>
<MenuItem value={'title'}>제목</MenuItem>
<MenuItem value={'content'}>내용</MenuItem>
<MenuItem value={'titleAndContent'}>제목+내용</MenuItem>
<MenuItem value={'writer'}>작성자</MenuItem>
</Select>
</FormControl>
<input type='text' placeholder='검색' onChange={handleChange} />
<div>
<button onClick={clickModal}>뒤로가기</button>
<button onClick={clickSearch}>검색</button>
</div>
</div>
</SearchModalBox>
)
}
export default FeedSearchModal
router.query에서 아까 보낸 검색 조건과 검색내용을 받는다.
그리고 그 값을 이용하여 검색 결과를 불러온다.
// FeedSearchResult.tsx
import { FeedContainer } from '../Feed.style'
import FeedPagination from '../FeedPagination'
import FeedRemote from '../FeedRemote'
import FeedSearchList from './FeedSearchList'
import LoadingLogo from '../../../Common/Loading/LoadingLogo'
import { RootState } from '../../../../store/store'
import { toast } from 'react-toastify'
import useGetFeedSearchData from '../../../../react-query/CommunityData/FeedSearchData'
import { useRouter } from 'next/router'
import { useSelector } from 'react-redux'
import { useState } from 'react'
const FeedSearchResult = () => {
const accessToken = useSelector((state: RootState) => state.token.token)
const router = useRouter()
const { type, search } = router.query
const [currentPage, setPageValue] = useState(1)
// react-query를 이용하여 데이터 불러옴
const { data, isLoading } = useGetFeedSearchData(type, search, currentPage)
const clickWrite = () => {
if (accessToken) router.push('/community/write')
else toast.error('로그인이 필요합니다!')
}
return (
<>
{!isLoading ? <FeedContainer>
<p>검색 : {search}</p>
<FeedSearchList searchList={data?.data.searchResult.responseContents} />
<FeedRemote clickWrite={clickWrite} />
<FeedPagination currentPage={currentPage} setCurrentPage={setPageValue} maxPage={data?.data?.searchResult?.totalPage} />
</FeedContainer> : <LoadingLogo />}
</>
)
}
export default FeedSearchResult
같이 협업한 백엔드 코드 개발자 github