-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from b-and-it/feat/21
Feat/21 Infinite Scrolling, Promotion View 완료
- Loading branch information
Showing
7 changed files
with
229 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,93 @@ | ||
import React,{useEffect, useState} from 'react' | ||
import React, { useEffect, useRef, useState, useCallback } from 'react' | ||
import SearchBox from './searchbox'; | ||
import SearchResult from './searchresult'; | ||
import { axiosAPI } from '../../../axios'; | ||
import { PromotionCard } from '../../../promotion/types/common'; | ||
import Loading from '../../../common/loading'; | ||
type Props = {} | ||
|
||
type Result = { | ||
promotion_id : number, | ||
img : string | undefined, | ||
band_name : string, | ||
title : string, | ||
location : string, | ||
date : string, | ||
price : string, | ||
like : boolean, | ||
like_num : number | ||
} | ||
|
||
const exampleDataList :Result[] = [ | ||
{ | ||
promotion_id: 0, | ||
img: undefined, | ||
band_name: "밴드 이름 1", | ||
title: "공연 Title 1", | ||
location: "위치 1", | ||
date: "2024.06.01 토", | ||
price: "40,000₩", | ||
like: true, | ||
like_num: 32 | ||
}, | ||
{ | ||
promotion_id: 1, | ||
img: undefined, | ||
band_name: "밴드 이름 2", | ||
title: "공연 Title 2", | ||
location: "위치 2", | ||
date: "2024.06.15 토", | ||
price: "50,000₩", | ||
like: false, | ||
like_num: 29 | ||
}, | ||
{ | ||
promotion_id: 2, | ||
img: undefined, | ||
band_name: "밴드 이름 3", | ||
title: "공연 Title 3", | ||
location: "위치 3", | ||
date: "2024.07.01 일", | ||
price: "30,000₩", | ||
like: false, | ||
like_num: 16 | ||
}, | ||
{ | ||
promotion_id: 3, | ||
img: undefined, | ||
band_name: "밴드 이름 4", | ||
title: "공연 Title 4", | ||
location: "위치 4", | ||
date: "2024.07.20 일", | ||
price: "45,000₩", | ||
like: false, | ||
like_num: 50 | ||
}, | ||
{ | ||
promotion_id: 4, | ||
img: undefined, | ||
band_name: "밴드 이름 5", | ||
title: "공연 Title 5", | ||
location: "위치 5", | ||
date: "2024.08.05 월", | ||
price: "35,000₩", | ||
like: false, | ||
like_num: 16 | ||
} | ||
]; | ||
|
||
const Search = (props: Props) => { | ||
const [query, setQuery] = useState(""); | ||
const [results, setResults] = useState(exampleDataList); | ||
const [results, setResults] = useState<PromotionCard[]>([]); | ||
const target = useRef<HTMLDivElement | null>(null); | ||
const [isFetching, setIsFetching] = useState(false); | ||
const [stop, setStop] = useState(false); | ||
const [page, setPage] = useState(0); // 현재 페이지를 추적 | ||
|
||
useEffect(() => { | ||
const filteredResults = exampleDataList.filter((result) => { | ||
return result.title.toLowerCase().includes(query.toLowerCase())}) | ||
|
||
setResults(filteredResults) | ||
console.log(filteredResults) | ||
},[query]) | ||
// 검색 결과를 가져오는 함수 | ||
const fetchResults = useCallback(async () => { | ||
if (isFetching || stop) return;// 이미 요청 중이거나 중지 상태이면 반환 | ||
setIsFetching(true); | ||
try { | ||
const res = query === "" | ||
? await axiosAPI.get(`/api/promotions?currentPage=${page}`) | ||
: await axiosAPI.get(`/api/promotions/search?currentPage=${page}&keyword=${encodeURIComponent(query)}`); | ||
console.log(res) | ||
const promotionResult = res.data.result.promotionList; | ||
if (promotionResult.length === 0) { | ||
setStop(true); // 더 이상 데이터가 없으면 중지 상태로 설정 | ||
} | ||
else { | ||
// 더 이상 데이터가 없는 경우 2 | ||
if(promotionResult.length > 0 && promotionResult.length < 10) { | ||
setStop(true); | ||
} | ||
setResults((prevResults) => [...prevResults, ...res.data.result.promotionList]); | ||
} | ||
} catch (err) { | ||
setStop(true); // 에러 발생 시 중지 상태로 설정 | ||
console.error(err); | ||
} finally { | ||
setIsFetching(false); // 요청 완료 후 isFetching 상태 변경 | ||
} | ||
}, [query, page, stop]); | ||
|
||
// 쿼리가 변경될 때 새로운 결과를 가져오기 | ||
useEffect(() => { | ||
setResults([]); | ||
setPage(0); | ||
setStop(false);// 새 검색 시 정지 상태 해제 | ||
}, [query]); | ||
|
||
return ( | ||
<div className='flex flex-col h-full w-full mt-5'> | ||
<SearchBox value={query} onChange={(e:React.ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}/> | ||
<SearchResult results={results}/> | ||
</div> | ||
|
||
) | ||
|
||
// 페이지가 변경될 때 결과를 가져오기 | ||
useEffect(() => { | ||
if (!stop) { | ||
fetchResults(); | ||
} | ||
}, [page, fetchResults, stop]); | ||
|
||
// 무한 스크롤을 위해 타겟 요소를 감시 | ||
useEffect(() => { | ||
const observer = new IntersectionObserver((entries) => { | ||
if (entries[0].isIntersecting && !isFetching && !stop) { | ||
setPage((prevPage) => prevPage + 1); | ||
} | ||
}, { | ||
root: null, | ||
rootMargin: '100px', | ||
threshold: 1.0 | ||
}); | ||
|
||
if (target.current) { | ||
observer.observe(target.current); | ||
} | ||
|
||
return () => { | ||
if (target.current) { | ||
observer.unobserve(target.current); | ||
} | ||
}; | ||
}, [isFetching, stop]); | ||
|
||
return ( | ||
<div className='flex flex-col h-full w-full mt-5'> | ||
<SearchBox value={query} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)} /> | ||
<SearchResult results={results} /> | ||
<div ref={target} style={{ height: '1px' }}></div> | ||
{isFetching && <Loading text={"공연을 등록중입니다."} isLoading={isFetching}/>} | ||
</div> | ||
) | ||
} | ||
|
||
export default Search | ||
export default Search; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.