[Refactor] pagination 상태 유지 개선(searchParams)#158
Conversation
- useSearchParams 적용하여 뒤로가기 시에도 검색어와 페이지 유지되도록 수정 - useEffect 통해 검색어 유지되도록 수정
📝 WalkthroughWalkthrough경험(Experience) 유형 필터링의 타입 시스템을 강타입 유니온( Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Page as Page Component
participant Router as React Router
participant API as API Query
participant Data as Data Fetching
User->>Page: 페이지 방문 or 필터 변경
Page->>Router: useSearchParams() 호출
Router-->>Page: URL 검색 파라미터 읽기
Page->>Page: type/page 파라미터 추출
alt 파라미터 변경
User->>Page: 필터/검색 입력
Page->>Router: updateSearchParams() 호출
Router->>Router: URL 업데이트
Note over Router: ?type=PROJECT&page=1
end
Page->>API: useGetExperienceList(type, page)
API->>Data: 서버 요청 (문자열 type)
Data-->>API: 데이터 반환
API-->>Page: 결과 데이터
Page->>User: UI 렌더링
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🚀 빌드 결과✅ 린트 검사 완료 |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/experience/api/use-experience-list.query.ts (1)
29-32:⚠️ Potential issue | 🟠 Major
queryKey와queryFn에서 falsy 값 처리가 불일치해요.queryKey: experienceQueryKey.list(type ?? "", page), // "" 으로 정규화 queryFn: () => getExperienceList({ type: type ?? undefined, page }), // undefined로 정규화이로 인해 캐시 동작에 문제가 발생할 수 있어요:
type=null,type="",type=undefined가 모두 같은 캐시 키("")를 공유하지만- 실제 API 호출은 다르게 동작해요 (
""vsundefined쿼리 파라미터)캐시 키와 API 호출이 일관되게 동작하도록 통일해주세요.
🔧 일관된 처리를 위한 제안
export const useGetExperienceList = ({ type, page, }: { type?: string | null; page: number; }) => { + const normalizedType = type || undefined; return useQuery({ - queryKey: experienceQueryKey.list(type ?? "", page), - queryFn: () => getExperienceList({ type: type ?? undefined, page }), + queryKey: experienceQueryKey.list(normalizedType ?? "", page), + queryFn: () => getExperienceList({ type: normalizedType, page }), }); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/experience/api/use-experience-list.query.ts` around lines 29 - 32, Normalize the `type` value the same way in both the cache key and the API call: choose a single canonical form (e.g., undefined) and apply it to both `experienceQueryKey.list(...)` and the call to `getExperienceList(...)` so the cache key matches the actual request parameters; specifically, update the `queryKey` invocation (experienceQueryKey.list) to accept the same normalized `type` as the `queryFn` that calls `getExperienceList` (both using type ?? undefined or both using type ?? ""), ensuring consistency between the cache key and the API request.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/pages/experience/experience-page.tsx`:
- Around line 34-39: handlePageChange currently uses an unnecessary nullish
coalescing (type ?? "") even though type is already derived from
searchParams.get("type") || "" and thus always a string; update the
handlePageChange function to pass type directly to setSearchParams (remove the
"?? \"\"" usage) so setSearchParams({ type: type, page: String(page) }) uses the
existing type variable from the searchParams.get("type") || "" initialization.
In `@src/widgets/experience-filter/experience-filter.tsx`:
- Line 22: Guard the cast of value to ExperienceTypeCode before indexing
EXPERIENCE_TYPE: replace the unvalidated cast in the experience-filter component
by checking membership first (e.g., if (value &&
Object.prototype.hasOwnProperty.call(EXPERIENCE_TYPE, value)) triggerLabel =
EXPERIENCE_TYPE[value as ExperienceTypeCode];) so that triggerLabel cannot
become undefined when an invalid string is passed; reference the symbols value,
EXPERIENCE_TYPE, ExperienceTypeCode, and triggerLabel in your change.
---
Outside diff comments:
In `@src/features/experience/api/use-experience-list.query.ts`:
- Around line 29-32: Normalize the `type` value the same way in both the cache
key and the API call: choose a single canonical form (e.g., undefined) and apply
it to both `experienceQueryKey.list(...)` and the call to
`getExperienceList(...)` so the cache key matches the actual request parameters;
specifically, update the `queryKey` invocation (experienceQueryKey.list) to
accept the same normalized `type` as the `queryFn` that calls
`getExperienceList` (both using type ?? undefined or both using type ?? ""),
ensuring consistency between the cache key and the API request.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0cdcf287-49f4-4da2-a5be-0ec5d6d95d1c
📒 Files selected for processing (8)
src/features/experience-detail/types/experience-detail.types.tssrc/features/experience-detail/ui/experience-viewer/experience-viewer.tsxsrc/features/experience/api/use-experience-list.query.tssrc/pages/experience/experience-page.tsxsrc/pages/home/search-section/search-section.tsxsrc/pages/matching-list/matching-list-page.tsxsrc/shared/api/generate/http-client.tssrc/widgets/experience-filter/experience-filter.tsx
| }: ExperienceFilterProps) => { | ||
| let triggerLabel = "경험 유형"; | ||
| if (value) triggerLabel = EXPERIENCE_TYPE[value]; | ||
| if (value) triggerLabel = EXPERIENCE_TYPE[value as ExperienceTypeCode]; |
There was a problem hiding this comment.
value가 유효한 ExperienceTypeCode인지 검증 없이 캐스팅해요.
experience-viewer.tsx에서는 value in EXPERIENCE_TYPE 검사를 수행한 후 캐스팅하지만, 여기서는 검증 없이 바로 캐스팅하고 있어요. 유효하지 않은 문자열이 전달되면 triggerLabel이 undefined가 될 수 있어요.
🛡️ 방어적 검사 추가 제안
let triggerLabel = "경험 유형";
-if (value) triggerLabel = EXPERIENCE_TYPE[value as ExperienceTypeCode];
+if (value && value in EXPERIENCE_TYPE) {
+ triggerLabel = EXPERIENCE_TYPE[value as ExperienceTypeCode];
+}
else if (isTouched && hasTotal) triggerLabel = "전체";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (value) triggerLabel = EXPERIENCE_TYPE[value as ExperienceTypeCode]; | |
| let triggerLabel = "경험 유형"; | |
| if (value && value in EXPERIENCE_TYPE) { | |
| triggerLabel = EXPERIENCE_TYPE[value as ExperienceTypeCode]; | |
| } | |
| else if (isTouched && hasTotal) triggerLabel = "전체"; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/widgets/experience-filter/experience-filter.tsx` at line 22, Guard the
cast of value to ExperienceTypeCode before indexing EXPERIENCE_TYPE: replace the
unvalidated cast in the experience-filter component by checking membership first
(e.g., if (value && Object.prototype.hasOwnProperty.call(EXPERIENCE_TYPE,
value)) triggerLabel = EXPERIENCE_TYPE[value as ExperienceTypeCode];) so that
triggerLabel cannot become undefined when an invalid string is passed; reference
the symbols value, EXPERIENCE_TYPE, ExperienceTypeCode, and triggerLabel in your
change.
✏️ Summary
📑 Tasks
페이지네이션의 상태가 유지되도록 리팩토링을 진행했습니다. 상세 페이지에서 '뒤로가기' 버튼을 통해 목록 페이지로 넘어왔을 때 이전 상태를 유지하려면 url에 목록에 관련된 정보들을 저장해야 하는데요, 이 때 페이지와 필터, 검색어 등 상태가 유지되어야 하는 정보들을 쿼리 파라미터로 넘겨 페이지를 옮겨다니더라도 상태가 유지되도록 구현해주었습니다.
``jsx
// matching-list-page.tsx
const [searchParams, setSearchParams] = useSearchParams();
const currentPage = Number(searchParams.get("page")) || 1;
const keyword = searchParams.get("keyword") || "";
👀 To Reviewer
리팩토링 과정에서 ExperienceFilter 컴포넌트의 value의 type을
string | null로 확장해주었습니다. 그 이유는 .. 제가 안정성을 위해 범위를 너무 좁혀놨더니 오히려 결합도가 지나치게 올라가서 하나 수정하려고 130913개의 파일을 건너야 하는 불상사가 발생하여서 리팩토링 하는 김에 같이 바꿔주었습니다!이 부분 수정하면서 http-client의 getRequestDto와, ExperienceRequestDto의
type과 getSummaryExperienceList 메소드의type의 타입을 string으로 수정해주었습니다. 또한 유진이가 작업한 파일에서이렇게 수정되었습니다! 타입이랑, label의 기본값 정도만 수정되어서 큰 문제는 없겠지만 그래도 알아두어야 할 거 같아 전달합니다 ~
📸 Screenshot
추추의 작업 이슈로 화면녹화를 못하네요 쩝 .. 테스트 직접 해보기 ~~~~ >_<
🔔 ETC
Summary by CodeRabbit
릴리스 노트
버그 수정
리팩토링