서론
간단하게 구현하려면 한없이 간단하게 구현 할 수 있지만..
실제 서버 올라가서 비용문제도 생각해야 하고, 리소스 문제 등등 실제 프로젝트 처럼 짜려다 보니 react는 처음 해보는데 되게 생각해야 하는 기능들이 많이 있었다.
일단 구현 자체는 되었지만 삽질 시간이 5~6시간은 되는 것 같아 조금 힘들다 ㅠ_ㅠ
풀스크린샷으로 찍어서 그런지 아직 화면에 그려지지 않은 얘들은 이미지가 노출이 안된다.
굉장히 좋군..
일단, 무한 스크롤로 화면 구현을 했고
검색창은 헤더에 달려있고
필터 목록은 검색 페이지 내에 달려있다.
실제로 디자이너들은 더 빡센 구조도 요청하는 경우가 많으니..
또 다른 페이지에 갔다 왔을 때 현재 검색 내용을 초기화 해서는 안된다..
무한 스크롤 특성상 상세 페이지 들어갔다가 뒤로 돌아오면 데이터가 유지 되어야 하는 점,
통신 비용 문제도 있다.
해결해야 하는 내용은 갑자기 확 늘었는데
1. 헤더에 달려있는 곳에서 Enter 시 현재 필터링 조건으로 검색이 되어야 한다.
2. 무한 스클로시 page가 늘어가면서 추가 데이터 요청을 해줘야 하고, 마지막 페이지면 데이터 요청을 하면 안된다.
3. 기존 검색이 끝나기 전에 검색 API가 재 요청이 들어가면 안된다.
4. 검색된 데이터는 필터 조건이 변경되지 않는 이상 유지 되어야 한다.
5. 검색 조건이 변경되면 page 값은 1로 검색 API를 재 요청 해야 한다.
인데, 위 조건들이 겹치니까 생각보다 서로 엮이는 곳이 많아 힘들었다.
위 내용들을 해결해보자..
4. 검색 데이터가 유지 되어야 한다에서, 데이터를 어딘가에 저장 해 두어야 한다는건 명확하다.
또, 무한스크롤 특성때문에라도 필수적인 내용이다.
따라서, Store 기능을 사용해서 구현하기로 했다.
대충 Store 관련 구현한거는 이전 포스트에 정리 해 두었다.
먼저, 검색 이벤트에는 아래와 같이 처리하였다.
const moveSearchPage = () => {
const searchValue = document.getElementById('searchOp').value
router.push({
pathname: '/operator',
query:{name:`${searchValue}`}
}, `/operator`)
}
const searchInputBind = (e) => {
setSaerchPrintOpName(e.target.value)
dispatch(operatorActions.setSearchOptionName(e.target.value))
}
const moveSearchPageKey = (e) => {
if(e.keyCode === 13) {
moveSearchPage()
}
}
Inupt쪽에 데이터를 바인딩 하면서, (vue 에서는 bind 쓰면 되는데 react는 조금 더 작성 해줘야 하더라 ㅠ_ㅠ..)
바인딩된 데이터를 store에 저장시켜서, 검색 조건을 계속 갱신해 준다.
keyUp시 마다 바인딩이 되겠지만, 최종적으로는 enter를 눌러 router가 push 될 때 query값으로 검색을 시켜줘야 한다.
오퍼레이터 목록 페이지에 접근 했을 때, 검색 API 호출을 다음과 같이 구현했다.
useEffect(() => {
if(searchOpValue.lastSearchOption.name !== searchOpValue.searchOption.name) {
setFirstPage()
}
if(searchOpValue.operatorList.length === 0 || !_.isEqual(searchOpValue.searchOption, searchOpValue.lastSearchOption)) {
searchOpApi()
}
}, [router.query, searchOpValue.searchOption.page, searchOpValue.searchOption.rarity, searchOpValue.searchOption.profession])
router query를 바라보게 하고, searchOption에서 name을 빼고 observe 시켜주고
검색 조건이 변경되지 않았을 때는 API를 재 신청하지 않도록 처리 했다.
또 한, 검색 조건이 변경 되었을 때는 store의 page값을 1로 두도록 (setFirstPage 함수) 구현해 두었다.
일단 이로써 위에 낸 1,2,4,5번은 해결이 되었고,
3번의 경우에는 평이하게 통신 종료와 관련된 bool값을 이용해서 처리 했다.
각 필터마다 Action이 다르다.. 일일히 짜기엔 ..
다른 문제는, 각 필터마다 onClick Action이 다르다는 것이다.
필터에 따라서 추가적인 필터가 노출 되는 것도 있을 것이고,
(현재는 아직 미구현 해 두었지만 베이스 자체를 구현 해 두었기 때문에 해당 부분은 추가 개발로 처리하면 바로 구현 가능 할 것 같다.)
세팅되는 option값도 전부 다르다..
html 안에 data를 사용해서 해결하면 세팅되는 option값은 처리하기 쉽지만 클릭시 이벤트를 각기 다르게 줘야하는건 조금 벅찬 문제.
jquery로 표현하면 각기 class명을 다르게 주고 .on을 사용하면 되긴 하겠지만 일단 함수 자체를 return 시키는 방법으로 구현해 보았다.
const printFilterList = [
{
name: "등급",
objName: "rarity",
appendClass: '',
clickEvent: (item) => setSelectedFilterRarity(item),
filterItem: [
{
printValue: 1,
value: 0,
appendClass: 'rarity0'
},
{
printValue: 2,
value: 1,
appendClass: 'rarity1'
},
{
printValue: 3,
value: 2,
appendClass: 'rarity2'
},
{
printValue: 4,
value: 3,
appendClass: 'rarity3'
},
{
printValue: 5,
value: 4,
appendClass: 'rarity4'
},
{
printValue: 6,
value: 5,
appendClass: 'rarity5'
},
]
},
{
name: "포지션",
objName: "profession",
appendClass: '',
clickEvent: (item) => setProfessionFilterEvent(item),
filterItem: [
{
printValue: "뱅가드",
value: "PIONEER",
appendClass: ''
},
{
printValue: "가드",
value: "WARRIOR",
appendClass: ''
},
{
printValue: "디펜더",
value: "TANK",
appendClass: ''
},
{
printValue: "스나이퍼",
value: "SNIPER",
appendClass: ''
},
{
printValue: "캐스터",
value: "CASTER",
appendClass: ''
},
{
printValue: "메딕",
value: "MEDIC",
appendClass: ''
},
{
printValue: "서포터",
value: "SUPPORT",
appendClass: ''
},
{
printValue: "스페셜리스트",
value: "SPECIAL",
appendClass: ''
},
]
}
]
추가 클래스를 구현 가능하게끔도 처리 해 두었고, 필터 구분별로 다른 clickEvent를 구현했다.
const printfilterJsx = printFilterList.map((filterGroup) => {
return <>
<div key={filterGroup.name} className={style.filterItemList}>
<div className={style.filterTitle}>{filterGroup.name}</div>
<div className={style.filterItem}>
{filterGroup.filterItem.map((filter) => {
return <>
<div key={filter.value} onClick={() => filterGroup.clickEvent(filter)} className={`${style.filter} ${searchOpValue.searchOption[filterGroup.objName].indexOf(filter.value) === -1 ? '' : style.selected}`}>{filter.printValue}</div>
</>
})}
</div>
</div>
</>
})
Jsx 구현시 onClick에 위와 같이 작성해서 클릭한 대상 데이터 자체를 onClick 함수에 넘길 수 있도록 처리했다.
이러면 jquery 에서 on 을 쓰는 것과 data를 사용하는 것과는 다르게 필터 데이터 자체에 접근이 가능하다.
(다른 방법으로느 index 처리 등으로 해당 obj를 다시 찾아야 하는 문제점도 있다..)
각 클릭 이벤트 안쪽에 store값을 갱신하도록 처리 해 주면 위에서 작성한 useEffect에서 저절로 검색이 된다.
언어 자체를 처음 써봐서 굉장히 복잡하게 된 거 같기도 하고,
잘 짠거 같기도 하고 잘 모르겠당..
일단 속도도 빠르고 필요없는 API 재호출, 화면 render를 나름 최소화 한 거 같으니 잘 한거 아닐까 싶기도 하다.
다음에는 상세페이지 구현을 해야겠다.. 이쪽도 당장은 주요 기능만 들어 갈 것 같다 ㅠㅠ..
'프로그래밍 일지 > 명빵' 카테고리의 다른 글
[개인프로젝트] 데이터 동기화 (0) | 2023.05.11 |
---|---|
[개인프로젝트] Redux->Mobx 전환 및 typescript로 변환 (0) | 2023.05.05 |
[개인프로젝트] EC2 Next.js App 배포 (Ubuntu + next.js + pm2 + nginx + Route53 + Ec2 LB) (0) | 2023.03.21 |
[개인프로젝트] EC2 Mysql, MongoDB Setting 및 data transper (0) | 2023.03.20 |
[개인프로젝트] EC2 laravel 배포 (Ubuntu22 nginx Laravel 배포) (0) | 2023.03.20 |