refactor: 프로필 섹션 구조 개선#194
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Walkthrough프로필 페이지 아키텍처를 서버 사이드 프리페칭 기반으로 재설계하고, Error Boundary와 Suspense로 경계 계층을 구성하며, 기존 prop 기반 로직을 재사용 가능한 훅으로 분리했습니다. 데이터 프리페칭, 로딩/에러 처리, 상태 관리 훅, 컴포넌트 구조 리팩터를 체계적으로 구현합니다. Changes프로필 섹션 구조 개선
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
features/profile/hooks/use-update-profile.mutation.ts (1)
11-13:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
my캐시도 함께 갱신해 주세요.여기서는
detail(profile.userId)만 덮어써서, 이번 PR에서 새로 분리한useMyProfile()쪽 캐시는 수정 전 값으로 남습니다. 내 프로필 수정 직후useIsMyProfile()나 다른 마이프로필 소비 지점이 stale 상태를 계속 볼 수 있으니profileKeys.my()도 같이 갱신하거나 관련 쿼리를 invalidate하는 편이 안전합니다.수정 예시
return useMutation({ mutationFn: updateProfile, onSuccess: (profile) => { queryClient.setQueryData(profileKeys.detail(profile.userId), profile); + queryClient.setQueryData(profileKeys.my(), profile); }, });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@features/profile/hooks/use-update-profile.mutation.ts` around lines 11 - 13, In the onSuccess handler of the mutation in use-update-profile.mutation.ts you only update profileKeys.detail(profile.userId), leaving the useMyProfile() cache stale; update the "my" cache as well by calling queryClient.setQueryData(profileKeys.my(), profile) (or alternatively call queryClient.invalidateQueries(profileKeys.my())) so consumers like useMyProfile() and useIsMyProfile() see the updated profile immediately.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/profile-examples/profile-examples-client.tsx`:
- Around line 7-15: The dynamic import for ProfileDetailView uses ssr: false so
the server renders only ProfileSectionSkeleton; remove the ssr: false option (or
set ssr: true) in the dynamic(...) call in profile-examples-client.tsx so the
actual ProfileDetailView is included in server HTML and the page can demonstrate
server-side prefetch/hydration; keep the loading fallback
(ProfileSectionSkeleton) if desired and ensure the import still resolves
mod.ProfileDetailView as the default.
In `@app/profile/`[userId]/page.tsx:
- Around line 24-27: The parser currently allows non-integer numbers (e.g.,
"1.5") so requests like /profile/1.5 proceed; update the validation so only
positive integers are accepted: either modify parsePositiveInt to return null
when Number.isInteger(parsed) is false, or add an explicit check after parsing
(e.g., if (!Number.isInteger(profileUserId)) return { title: '프로필' } or call
notFound()) before metadata/profile lookup; target the parsePositiveInt function
and the usage around profileUserId and notFound() to ensure fractional IDs are
rejected.
- Around line 43-51: You're prefetching the authenticated profile
unconditionally (queryClient.prefetchQuery with queryKey profileKeys.my and
queryFn fetchMyProfile) which runs on the server even when no auth is present;
change the logic to only prefetch profileKeys.my when the server request
actually contains authentication (e.g., inspect incoming cookies/authorization
header in the SSR context) and skip the prefetch otherwise so the client-side
useMyProfile guard (enabled when token exists) handles it; keep the existing
unconditional prefetch for profileKeys.detail(profileUserId)/fetchProfileById
but wrap or gate the fetchMyProfile prefetch behind an auth check.
In `@features/profile/components/profile-section.tsx`:
- Around line 15-19: Wrap the server-side prefetch in
app/profile/[userId]/page.tsx (the queryClient.prefetchQuery call that primes
fetchProfileById(profileUserId)) in a try/catch, catch errors thrown by
shared/lib/response-parser (ApiError) and if err.status === 404 call notFound(),
otherwise rethrow; keep parsePositiveInt validation as-is and do not change
throwOnError in shared/lib/get-query-client.ts; this ensures missing profiles
are promoted to notFound() before rendering reaches the client-side
ProfileSectionBoundary.
In `@features/review/components/review-list/user-review-container.tsx`:
- Around line 12-13: UserReviewContainer currently calls useIsMyProfile(), which
indirectly calls useMyProfile() and can suspend/error outside
ProfileSectionBoundary; either move the ownership check into a component that is
rendered inside ProfileSectionBoundary or replace the call here with a
non-suspending ownership path (e.g., read current user id from a synchronous
source or create a useIsMyProfileNonSuspense that checks ownership without
calling useMyProfile). Locate UserReviewContainer and change the ownership logic
so this top-level container never calls useIsMyProfile/useMyProfile directly (or
wrap UserReviewContainer with its own ErrorBoundary/Suspense) to ensure the
review area still hits the PR’s fallback/retry UI when profile fetches
suspend/error.
In `@shared/lib/parse-positive-int.ts`:
- Around line 1-3: The parsePositiveInt function currently treats positive
non-integer numbers (e.g., 1.5) as valid; update parsePositiveInt to also verify
the parsed value is an integer by using Number.isInteger(number) alongside
Number.isFinite(number) and number > 0 so only positive integers pass (keep the
same return signature number | null and the same behavior of returning null for
invalid inputs).
---
Outside diff comments:
In `@features/profile/hooks/use-update-profile.mutation.ts`:
- Around line 11-13: In the onSuccess handler of the mutation in
use-update-profile.mutation.ts you only update
profileKeys.detail(profile.userId), leaving the useMyProfile() cache stale;
update the "my" cache as well by calling
queryClient.setQueryData(profileKeys.my(), profile) (or alternatively call
queryClient.invalidateQueries(profileKeys.my())) so consumers like
useMyProfile() and useIsMyProfile() see the updated profile immediately.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 35b8ea38-7849-406f-9b73-40132147fc87
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (29)
app/profile-examples/page.tsxapp/profile-examples/profile-examples-client.tsxapp/profile/[userId]/_components/profile-detail-view.tsxapp/profile/[userId]/page.tsxapp/profile/[userId]/profile-page-client.tsxfeatures/profile/api/fetch-my-profile.tsfeatures/profile/api/fetch-profile-by-id.tsfeatures/profile/api/update-profile.tsfeatures/profile/components/profile-edit-form.tsxfeatures/profile/components/profile-owner-actions.tsxfeatures/profile/components/profile-page-content.tsxfeatures/profile/components/profile-section-boundary.tsxfeatures/profile/components/profile-section-skeleton.tsxfeatures/profile/components/profile-section.tsxfeatures/profile/hooks/use-is-my-profile.tsfeatures/profile/hooks/use-my-profile.query.tsfeatures/profile/hooks/use-profile-by-id.query.tsfeatures/profile/hooks/use-profile-edit-form.tsfeatures/profile/hooks/use-profile-editing.tsfeatures/profile/hooks/use-profile-share.tsfeatures/profile/hooks/use-update-profile.mutation.tsfeatures/profile/index.tsfeatures/profile/queries.tsfeatures/profile/query-keys.tsfeatures/review/components/review-list/user-review-container.tsxpackage.jsonshared/components/retry-error-state.tsxshared/lib/api/resolve-api-url.tsshared/lib/parse-positive-int.ts
💤 Files with no reviewable changes (3)
- features/profile/queries.ts
- features/profile/components/profile-page-content.tsx
- app/profile/[userId]/profile-page-client.tsx
📝 개요
Note
현재 token을 client에 저장하고 있기 때문에 console에 error가 표시되고 있어요. 이 부분은 백엔드에서 cookie 기반으로 변경하도록 해주어야 에러를 없앨 수 있고, 더 완전한 ssr을 사용할 수 있을것 같아요. 추가적으로 이번 PR에는 프로필(페이지 내 상단)만 리팩토링 해두었어요
🔗 관련 이슈
🛠️ 변경 사항 (Checklist)
✅ 아래 내용을 한 번 더 점검해 주세요
1. 의도와 가독성 (Naming & Readability)
2. 타입과 논리 (Type Safety & Logic)
any사용을 지양하고, 모든 함수의 반환 타입을 명시했나요?null/undefined), 에러가 발생할 경우를 처리했나요?3. 코드 다이어트 (Clean-up)
console.log나 사용하지 않는import를 모두 지웠나요?4. 지속 가능성 (Sustainability)
README업데이트가 필요한가요?💭 회고 (Optional)
Summary by CodeRabbit
릴리스 노트
새로운 기능
버그 수정
개선사항