-
Notifications
You must be signed in to change notification settings - Fork 2
[feat] 팔로잉/팔로워 목록 페이지 퍼블리싱 #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
📝 Walkthrough워크스루팔로잉/팔로워 목록 페이지 퍼블리싱을 위한 새로운 피드 레이아웃 및 페이지 컴포넌트를 추가하고, FollowButton을 단순화하며, ContentHeader를 확장하여 정렬 옵션과 카운트 타입을 동적으로 지원하고, 새로운 사용자 기반 라우팅을 구성했습니다. 변경 사항
예상 코드 리뷰 노력🎯 3 (보통) | ⏱️ ~25분 시
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 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 |
Summary of ChangesHello @maylh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 팔로잉/팔로워 목록 페이지를 퍼블리싱하고, 관련 피드 페이지의 폴더 구조와 사용자 ID 기반 라우팅을 설정합니다. 또한, ContentHeader 컴포넌트를 리팩토링하여 정렬 옵션을 동적으로 구성할 수 있도록 유연성을 높였습니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
🎵 Storybook Link 🎵 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@src/features/follow/ui/FollowButton.tsx`:
- Line 21: The login check in FollowButton is using useAuthStore() without a
selector so it always returns a truthy store object; update the call to
useAuthStore to select the actual auth flag or user (e.g., useAuthStore(state =>
state.isLoggedIn or state.user)) and rename the variable from isLogin to
something like isLoggedIn; then use that boolean in the FollowButton click
handler (and any checks around openLoginModal or toggleFollow) so
unauthenticated users trigger the login modal instead of running the follow
toggle.
In `@src/pages/feed/FeedLayout.tsx`:
- Around line 3-11: The component declared as UserLayout in FeedLayout.tsx is
misnamed and unnecessarily wrapped in a Fragment; either rename the component to
FeedLayout (change function UserLayout to function FeedLayout) and update the
default export to export default FeedLayout, or rename the file to match
UserLayout; also remove the unnecessary Fragment and return Outlet directly
(e.g., return <Outlet />) inside the FeedLayout/UserLayout function.
In `@src/pages/feed/FollowLayout.tsx`:
- Around line 24-29: The ContentHeader call currently passes a hardcoded
totalCount={2}; replace this placeholder with the real data source (e.g., a prop
or state value such as followersCount, followingCount, or totalCount derived in
FollowLayout) or add a clear TODO comment if left for publishing; update the JSX
where ContentHeader is used (the totalCount prop on ContentHeader) to accept the
dynamic value (or add a TODO above that line referencing the data to be wired)
and ensure the selected and onSelect props remain unchanged.
- Line 20: The center prop currently renders a hardcoded name ("홍길동"); replace
this by reading the route param and/or fetching the real user name: import and
call useParams() in the FollowLayout component to get userId, then either
display userId or call your existing user-fetching function/ hook (e.g.,
fetchUser, useUser or an API client) to resolve and render the real name in the
center prop; if this is intentionally a placeholder, add a TODO comment near
FollowLayout noting it should be replaced with real data before publishing.
In `@src/shared/config/routesConfig.ts`:
- Around line 131-143: 자식 라우트에서 절대 경로('/:userId/followers' 및
'/:userId/following')를 사용하고 있어 부모 경로와 중복되며 매칭 오류를 일으킬 수 있으니, FollowLayout의
children 항목에서 path를 부모에 상대적인 'followers' 및 'following'으로 변경하여 FollowLayout →
Followers/Following 중첩 라우팅이 정상 동작하도록 수정하세요; 대상 식별자: FollowLayout, Followers,
Following, 문제 있는 path 문자열('/:userId/followers', '/:userId/following').
In `@src/stories/ContentHeader.stories.tsx`:
- Line 48: The story example uses countType="number" but the component expects
the CountType union ('NUMBER' | 'PEOPLE') and the actual render uses
countType="NUMBER"; update the example prop to use the uppercase literal
"NUMBER" so the example matches the rendered usage and the CountType type
(change the countType prop in the example in ContentHeader.stories to "NUMBER").
🧹 Nitpick comments (7)
src/features/follow/ui/FollowButton.tsx (1)
13-19: 미사용userIdprop
userId가 props 인터페이스에 선언되어 있지만, 컴포넌트에서 destructure 및 사용되지 않습니다. 현재 불필요하다면 제거하거나, 향후 API 연동 시 필요하다면 TODO 주석을 추가해 주세요.src/shared/ui/ContentHeader.tsx (1)
58-68: BottomSheet 높이가200px로 고정
options배열 길이에 따라 BottomSheet 내용 크기가 달라질 수 있습니다. 옵션이 3개(RECENT, POPULAR, OLDEST)면180px(60px × 3)이 필요하고, 2개면120px이면 충분합니다. 현재는 큰 문제가 아니지만, 옵션 수에 따라 높이를 동적으로 계산하는 것을 고려해 볼 수 있습니다.src/pages/feed/following/index.tsx (2)
9-22: 변수명이 페이지 의미와 불일치
Following페이지에서 데이터 변수명이followerList로 되어 있습니다. 팔로잉 목록이므로followingList가 더 적절합니다.
29-40:SearchResultItem에 중복keypropLine 30의
ItemWrapper에 이미key={item.userId}가 있으므로, Line 32의SearchResultItem에 있는key는 불필요합니다.♻️ 수정 제안
<ItemWrapper key={item.userId}> <SearchResultItem - key={item.userId} type="USER" imageUrl={item.profileUrl} searchResult={item.userName} onClick={() => navigate(`/${item.userId}`)} />src/pages/feed/followers/index.tsx (2)
29-40:SearchResultItem에 중복keyprop (following 페이지와 동일)
ItemWrapper에 이미key가 있으므로SearchResultItem의key는 제거해 주세요.♻️ 수정 제안
<ItemWrapper key={item.userId}> <SearchResultItem - key={item.userId} type="USER"
1-57:followers와following페이지 간 코드 중복
followers/index.tsx와following/index.tsx의 렌더링 로직,ItemWrapper,ListWrapper스타일드 컴포넌트가 거의 동일합니다. 퍼블리싱 단계에서는 허용 가능하지만, API 연동 시 공통 리스트 컴포넌트(예:FollowList)로 추출하는 것을 권장합니다.src/shared/config/routesConfig.ts (1)
123-128: 와일드카드*라우트가/:userId보다 앞에 위치react-router v6+는 경로 랭킹 기반 매칭을 사용하므로 순서상 문제가 발생하지 않을 수 있지만, 가독성과 명확성을 위해 와일드카드(
*) 라우트를 설정 배열의 마지막에 배치하는 것이 관례입니다. 또한/:userId는 모든 단일 세그먼트 경로와 매칭되므로,/error,/feedback등 정적 경로와의 충돌 여부를 확인해 주세요.#!/bin/bash # routesConfig에서 라우트 소비 방식 확인 (createBrowserRouter 등) rg -n "routesConfig" --type=ts --type=tsx -C5
| const navigate = useNavigate() | ||
| const { isLogin } = useAuthStore() | ||
| const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false) | ||
| const isLogin = useAuthStore() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useAuthStore() 셀렉터 누락으로 로그인 체크가 항상 truthy
useAuthStore()는 셀렉터 없이 호출하면 전체 스토어 객체를 반환하므로 항상 truthy입니다. 따라서 비로그인 사용자도 로그인 모달이 표시되지 않고 팔로우 토글이 실행됩니다.
🐛 수정 제안
- const isLogin = useAuthStore()
+ const isLogin = useAuthStore((state) => state.isLogin)📝 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.
| const isLogin = useAuthStore() | |
| const isLogin = useAuthStore((state) => state.isLogin) |
🤖 Prompt for AI Agents
In `@src/features/follow/ui/FollowButton.tsx` at line 21, The login check in
FollowButton is using useAuthStore() without a selector so it always returns a
truthy store object; update the call to useAuthStore to select the actual auth
flag or user (e.g., useAuthStore(state => state.isLoggedIn or state.user)) and
rename the variable from isLogin to something like isLoggedIn; then use that
boolean in the FollowButton click handler (and any checks around openLoginModal
or toggleFollow) so unauthenticated users trigger the login modal instead of
running the follow toggle.
| const UserLayout = () => { | ||
| return ( | ||
| <> | ||
| <Outlet /> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| export default UserLayout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
파일명과 컴포넌트명 불일치
파일명은 FeedLayout.tsx이지만 컴포넌트명은 UserLayout입니다. 네이밍 일관성을 위해 둘 중 하나를 맞춰주세요. 또한 자식이 <Outlet />뿐이므로 Fragment(<>...</>)는 불필요합니다.
♻️ 제안
-const UserLayout = () => {
- return (
- <>
- <Outlet />
- </>
- )
-}
-
-export default UserLayout
+const FeedLayout = () => {
+ return <Outlet />
+}
+
+export default FeedLayout📝 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.
| const UserLayout = () => { | |
| return ( | |
| <> | |
| <Outlet /> | |
| </> | |
| ) | |
| } | |
| export default UserLayout | |
| const FeedLayout = () => { | |
| return <Outlet /> | |
| } | |
| export default FeedLayout |
🤖 Prompt for AI Agents
In `@src/pages/feed/FeedLayout.tsx` around lines 3 - 11, The component declared as
UserLayout in FeedLayout.tsx is misnamed and unnecessarily wrapped in a
Fragment; either rename the component to FeedLayout (change function UserLayout
to function FeedLayout) and update the default export to export default
FeedLayout, or rename the file to match UserLayout; also remove the unnecessary
Fragment and return Outlet directly (e.g., return <Outlet />) inside the
FeedLayout/UserLayout function.
| <HeaderSection> | ||
| <Header | ||
| left={<SvgButton icon={LeftArrow} onClick={() => navigate(-1)} />} | ||
| center={<span>홍길동</span>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
하드코딩된 사용자 이름 "홍길동"을 라우트 파라미터 또는 API 데이터로 교체 필요
/:userId 라우트 하위에서 렌더링되는 컴포넌트이므로, useParams로 userId를 가져와 실제 사용자 이름을 표시해야 합니다. 퍼블리싱 단계에서 의도적인 플레이스홀더라면 TODO 주석을 남겨주세요.
💡 제안
- center={<span>홍길동</span>}
+ center={<span>홍길동</span>} {/* TODO: userId 기반 사용자 이름 조회로 교체 - maylh */}📝 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.
| center={<span>홍길동</span>} | |
| center={<span>홍길동</span>} {/* TODO: userId 기반 사용자 이름 조회로 교체 - maylh */} |
🤖 Prompt for AI Agents
In `@src/pages/feed/FollowLayout.tsx` at line 20, The center prop currently
renders a hardcoded name ("홍길동"); replace this by reading the route param and/or
fetching the real user name: import and call useParams() in the FollowLayout
component to get userId, then either display userId or call your existing
user-fetching function/ hook (e.g., fetchUser, useUser or an API client) to
resolve and render the real name in the center prop; if this is intentionally a
placeholder, add a TODO comment near FollowLayout noting it should be replaced
with real data before publishing.
| <ContentHeader | ||
| totalCount={2} | ||
| currentSort={selected} | ||
| onSortChange={onSelect} | ||
| options={['RECENT', 'OLDEST']} | ||
| countType="PEOPLE" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
하드코딩된 totalCount={2} — 실제 데이터 연동 시 교체 필요
팔로워/팔로잉 수도 플레이스홀더로 보입니다. 퍼블리싱 목적이라면 TODO 주석을 추가해 주세요.
🤖 Prompt for AI Agents
In `@src/pages/feed/FollowLayout.tsx` around lines 24 - 29, The ContentHeader call
currently passes a hardcoded totalCount={2}; replace this placeholder with the
real data source (e.g., a prop or state value such as followersCount,
followingCount, or totalCount derived in FollowLayout) or add a clear TODO
comment if left for publishing; update the JSX where ContentHeader is used (the
totalCount prop on ContentHeader) to accept the dynamic value (or add a TODO
above that line referencing the data to be wired) and ensure the selected and
onSelect props remain unchanged.
| children: [ | ||
| { | ||
| path: '/:userId/followers', | ||
| component: FollowLayout, | ||
| isNotSuspense: true, | ||
| children: [{ path: '', component: Followers }], | ||
| }, | ||
| { | ||
| path: '/:userId/following', | ||
| component: FollowLayout, | ||
| isNotSuspense: true, | ||
| children: [{ path: '', component: Following }], | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
중첩 라우트에서 절대 경로 사용 — 라우팅 오류 가능성
이 파일의 다른 중첩 라우트(예: Line 59의 '', Line 60의 ':id')는 모두 상대 경로를 사용하고 있습니다. 그런데 Line 133과 139에서는 /:userId/followers, /:userId/following처럼 절대 경로를 사용하고 있어 기존 패턴과 불일치합니다.
react-router-dom v7에서 중첩 라우트의 path는 부모 경로에 상대적으로 해석되므로, 부모가 이미 /:userId인 상태에서 자식에 다시 /:userId/...를 쓰면 의도와 다르게 동작하거나 매칭이 실패할 수 있습니다.
🐛 수정 제안: 상대 경로로 변경
children: [
{
- path: '/:userId/followers',
+ path: 'followers',
component: FollowLayout,
isNotSuspense: true,
children: [{ path: '', component: Followers }],
},
{
- path: '/:userId/following',
+ path: 'following',
component: FollowLayout,
isNotSuspense: true,
children: [{ path: '', component: Following }],
},
],#!/bin/bash
# 다른 중첩 라우트에서 절대 경로 vs 상대 경로 사용 패턴 확인
rg -n "path:" --type=ts -A0 src/shared/config/routesConfig.ts🤖 Prompt for AI Agents
In `@src/shared/config/routesConfig.ts` around lines 131 - 143, 자식 라우트에서 절대
경로('/:userId/followers' 및 '/:userId/following')를 사용하고 있어 부모 경로와 중복되며 매칭 오류를 일으킬
수 있으니, FollowLayout의 children 항목에서 path를 부모에 상대적인 'followers' 및 'following'으로
변경하여 FollowLayout → Followers/Following 중첩 라우팅이 정상 동작하도록 수정하세요; 대상 식별자:
FollowLayout, Followers, Following, 문제 있는 path 문자열('/:userId/followers',
'/:userId/following').
| currentSort={selected} | ||
| onSortChange={onSelect} | ||
| options={['RECENT', 'POPULAR']} | ||
| countType="number" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스토리 문서의 예시 코드에서 countType 값이 불일치합니다.
Line 48의 예시에서 countType="number"(소문자)로 작성되어 있지만, Line 67의 실제 렌더 코드에서는 countType="NUMBER"(대문자)를 사용하고 있습니다. CountType은 'NUMBER' | 'PEOPLE'이므로 예시도 대문자로 수정해야 합니다.
📝 수정 제안
- countType="number"
+ countType="NUMBER"🤖 Prompt for AI Agents
In `@src/stories/ContentHeader.stories.tsx` at line 48, The story example uses
countType="number" but the component expects the CountType union ('NUMBER' |
'PEOPLE') and the actual render uses countType="NUMBER"; update the example prop
to use the uppercase literal "NUMBER" so the example matches the rendered usage
and the CountType type (change the countType prop in the example in
ContentHeader.stories to "NUMBER").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request successfully establishes the publishing and routing structure for the following/follower list pages, and commendably refactors the ContentHeader component for enhanced flexibility. However, a significant security vulnerability has been identified: a medium-severity Open Redirect in src/pages/feed/ui/FollowTab.tsx. This issue stems from using unsanitized user input from the URL to construct redirect paths, which could enable attackers to craft malicious links. It is crucial to address this vulnerability promptly. Additionally, the review highlighted several areas for improvement: an error in the nested route path configuration within routesConfig.ts, a bug in the FollowButton component concerning login status checks and missing follow functionality, and adherence to style guidelines, including naming conventions and the use of magic numbers, across the new pages. Regarding architectural considerations, moving FollowLayout and FollowTab to a shared src/pages/feed/ui/layouts folder is a good practice for future scalability, and the mypage/ui structure aligns well with FSD principles. Please refer to the specific file comments for detailed feedback and the recommended fix for the Open Redirect vulnerability.
| const navigate = useNavigate() | ||
| const { isLogin } = useAuthStore() | ||
| const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false) | ||
| const isLogin = useAuthStore() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| children: [ | ||
| { | ||
| path: '/:userId/followers', | ||
| component: FollowLayout, | ||
| isNotSuspense: true, | ||
| children: [{ path: '', component: Followers }], | ||
| }, | ||
| { | ||
| path: '/:userId/following', | ||
| component: FollowLayout, | ||
| isNotSuspense: true, | ||
| children: [{ path: '', component: Following }], | ||
| }, | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
react-router-dom v6에서 중첩 라우트(children)의 경로는 부모 경로에 상대적으로 설정되어야 합니다. 현재 followers와 following 경로가 /:userId/followers와 같이 절대 경로로 작성되어 있어 라우팅이 정상적으로 동작하지 않습니다. 부모 경로인 /:userId를 기준으로 상대 경로인 'followers'와 'following'으로 수정해야 합니다.
| children: [ | |
| { | |
| path: '/:userId/followers', | |
| component: FollowLayout, | |
| isNotSuspense: true, | |
| children: [{ path: '', component: Followers }], | |
| }, | |
| { | |
| path: '/:userId/following', | |
| component: FollowLayout, | |
| isNotSuspense: true, | |
| children: [{ path: '', component: Following }], | |
| }, | |
| ], | |
| children: [ | |
| { | |
| path: 'followers', | |
| component: FollowLayout, | |
| isNotSuspense: true, | |
| children: [{ path: '', component: Followers }], | |
| }, | |
| { | |
| path: 'following', | |
| component: FollowLayout, | |
| isNotSuspense: true, | |
| children: [{ path: '', component: Following }], | |
| }, | |
| ], |
| if (isLogin) { | ||
| toggleFollow() | ||
| setIsBottomSheetOpen(false) | ||
| setFollowing((prev) => !prev) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <TabButton to={`/${userId}/following`}>팔로잉</TabButton> | ||
|
|
||
| <TabButton to={`/${userId}/followers`}>팔로워</TabButton> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The userId parameter, obtained from the URL via useParams(), is used directly in the to prop of NavLink components. An attacker can craft a malicious URL with a path traversal payload (e.g., ../admin) in the userId segment. When a user clicks on the generated links, they could be redirected to an unintended page within the application, potentially leading to unauthorized access to other parts of the application. This is a form of Open Redirect.
| <TabButton to={`/${userId}/following`}>팔로잉</TabButton> | |
| <TabButton to={`/${userId}/followers`}>팔로워</TabButton> | |
| <TabButton to={`/${encodeURIComponent(userId)}/following`}>팔로잉</TabButton> | |
| <TabButton to={`/${encodeURIComponent(userId)}/followers`}>팔로워</TabButton> |
| playlistId: number | ||
| userName: string | ||
| profile?: string | ||
| userId?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| center={<span>홍길동</span>} | ||
| /> | ||
| <FollowTab /> | ||
| <ContentHeaderWrapper> | ||
| <ContentHeader | ||
| totalCount={2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스타일 가이드 1.4에 따라, 의미를 알 수 없는 문자열이나 숫자인 '매직 넘버/스트링'의 사용을 지양해야 합니다. 현재 헤더에 사용자 이름이 '홍길동'으로, ContentHeader의 totalCount가 2로 하드코딩되어 있습니다. 퍼블리싱을 위한 임시 데이터라도, 상수로 분리하거나 추후 실제 데이터를 받아올 부분임을 명시하는 것이 좋습니다.
References
- 의미를 알 수 없는 숫자나 문자열(매직 넘버/스트링) 대신 명명된 상수를 사용합니다. (link)
| const followerList = [ | ||
| { | ||
| userId: '1', | ||
| profileUrl: '', | ||
| userName: '지구젤리', | ||
| isFollowing: true, | ||
| }, | ||
| { | ||
| userId: '2', | ||
| profileUrl: '', | ||
| userName: '김들락', | ||
| isFollowing: false, | ||
| }, | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스타일 가이드 1.2에 따라, 컴포넌트 외부의 상수 데이터는 UPPER_SNAKE_CASE로 명명해야 합니다. followerList를 FOLLOWER_LIST로 변경하는 것을 제안합니다.
| const followerList = [ | |
| { | |
| userId: '1', | |
| profileUrl: '', | |
| userName: '지구젤리', | |
| isFollowing: true, | |
| }, | |
| { | |
| userId: '2', | |
| profileUrl: '', | |
| userName: '김들락', | |
| isFollowing: false, | |
| }, | |
| ] | |
| const FOLLOWER_LIST = [ |
References
- 상수는 대문자 스네이크 케이스(UPPER_SNAKE_CASE)를 사용합니다 (예: API_BASE_URL, MAX_ITEM_COUNT). (link)
| {followerList?.map((item) => ( | ||
| <ItemWrapper key={item.userId}> | ||
| <SearchResultItem | ||
| key={item.userId} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const followerList = [ | ||
| { | ||
| userId: '1', | ||
| profileUrl: '', | ||
| userName: '지구젤리', | ||
| isFollowing: true, | ||
| }, | ||
| { | ||
| userId: '2', | ||
| profileUrl: '', | ||
| userName: '김들락', | ||
| isFollowing: true, | ||
| }, | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
팔로잉 목록 페이지임에도 불구하고 변수명이 followerList로 되어 있어 혼동을 줄 수 있습니다. followingList와 같이 페이지의 역할에 맞는 명확한 이름으로 변경하는 것이 좋습니다. 또한, 스타일 가이드 1.2에 따라 상수는 UPPER_SNAKE_CASE로 명명해야 하므로 FOLLOWING_LIST로 변경하는 것을 제안합니다.
| const followerList = [ | |
| { | |
| userId: '1', | |
| profileUrl: '', | |
| userName: '지구젤리', | |
| isFollowing: true, | |
| }, | |
| { | |
| userId: '2', | |
| profileUrl: '', | |
| userName: '김들락', | |
| isFollowing: true, | |
| }, | |
| ] | |
| const FOLLOWING_LIST = [ |
References
- 변수, 함수, 상수는 명확하고 의미론적이며 일관성을 유지하도록 명명해야 합니다. 상수는 UPPER_SNAKE_CASE를 사용합니다. (link)
| {followerList?.map((item) => ( | ||
| <ItemWrapper key={item.userId}> | ||
| <SearchResultItem | ||
| key={item.userId} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hansololiviakim
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
구조 정리 감사합니다 👏
말씀주신대로 마이페이지는 중첩 경로가 너무 많아서 UI에 해당 경로 묶어두고, 각 페이지들은 Next.js app route처럼 최대한 UI만 구현하는 로직이 들어가도록 짜뒀어요! (내부에서 step 돌아가는 customize 제외..)
🛰️ 관련 이슈
✨ 주요 변경 사항
1️⃣ 팔로잉/팔로워 목록 페이지 퍼블리싱
2️⃣ feed 관련 페이지 폴더구조 세팅 및 유저아이디 기반 라우팅 처리
🔍 테스트 방법 / 체크리스트
🗯️ PR 포인트
1️⃣ 팔로잉/팔로워 목록 페이지 퍼블리싱 관련
2️⃣ feed 관련 페이지 폴더구조 세팅 및 유저아이디 기반 라우팅 처리
ui내에layout하나 두고 폴더링 해주면 좋을 것 같아요 !mypage의 경우는mypage/ui/(중첩경로들)이런 식으로 경로들이 ui로 한번 더 묶여있던데 혹시 이거 따로 이유가 있나요 ? 경로가 너무 많아서 묶어주는 용도인건가요 ?🚀 알게된 점
📖 참고 자료 (선택)
Summary by CodeRabbit
릴리즈 노트
새로운 기능
리팩토링