Skip to content
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

카테고리별 게시글 조회 기능을 위해 getPostList 함수 수정 이후 usePostList 훅 추가 기능 구현 #113

Merged
merged 7 commits into from
Jul 25, 2023
Merged
11 changes: 11 additions & 0 deletions frontend/__test__/api/postList.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,15 @@ describe('전체 게시글 목록을 패치하는 로직이 의도한대로 작

expect(data.pageNumber).toEqual(3);
});

test('카테고리별 게시글 페이지의 정보를 불러온다.', async () => {
const data = await getPostList({
postStatus: 'closed',
postSorting: 'popular',
pageNumber: 3,
categoryId: 1,
});

expect(data.postList).toEqual(MOCK_POST_LIST[3]);
});
});
13 changes: 12 additions & 1 deletion frontend/__test__/hooks/query/usePostList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const wrapper = ({ children }: { children: ReactNode }) => (
);

describe('usePostList 훅이 의도한대로 작동하는 지 확인한다.', () => {
test('게시글 목록을 불러온다.', async () => {
test('전체 게시글 목록을 불러온다.', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

const { result } = renderHook(
() => usePostList({ postSorting: 'popular', postStatus: 'all' }),
{
Expand All @@ -24,4 +24,15 @@ describe('usePostList 훅이 의도한대로 작동하는 지 확인한다.', ()

await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST[0]));
});

test('카테고리별 게시글 목록을 불러온다.', async () => {
const { result } = renderHook(
() => usePostList({ postSorting: 'popular', postStatus: 'all', categoryId: 1 }),
{
wrapper,
}
);

await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST[0]));
});
});
25 changes: 20 additions & 5 deletions frontend/src/api/wus/postList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import type { PostSorting, PostStatus } from '@components/post/PostListPage/type

import { getFetch } from '@utils/fetch';

interface GetPostList {
interface PostListByOption {
postStatus: PostStatus;
postSorting: PostSorting;
pageNumber: number;
categoryId?: number;
}

const REQUEST_STATUS_OPTION: Record<PostStatus, string> = {
Expand All @@ -21,13 +22,27 @@ const REQUEST_SORTING_OPTION: Record<PostSorting, string> = {
popular: 'HOT',
};

export const getPostList = async ({ postStatus, postSorting, pageNumber }: GetPostList) => {
const getPostListUrl = ({ categoryId, postStatus, postSorting, pageNumber }: PostListByOption) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개인적인 취향이지만 가지고 오는 것보다는 만드는 것에 가깝다고 생각이 들어서

const makePostListUrl = ({ categoryId, postStatus, postSorting, pageNumber }: PostListByOption) => {

어떤지 궁금합니다! 그냥 선호여서 넘어가도 좋아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수아의 제안대로 get보다는 make가 더 어울리는 것 같아 수정해보았습니다 💯💯💯

export const makePostListUrl = ({
  categoryId,
  postStatus,
  postSorting,
  pageNumber,
}: PostListByOption) => {
  const requestedStatus = REQUEST_STATUS_OPTION[postStatus];
  const requestedSorting = REQUEST_SORTING_OPTION[postSorting];

  const OPTION_URL = `status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`;

  if (categoryId) {
    return `/posts?categoryId=${categoryId}&${OPTION_URL}`;
  }

  return `/posts?${OPTION_URL}`;
};

const requestedStatus = REQUEST_STATUS_OPTION[postStatus];
const requestedSorting = REQUEST_SORTING_OPTION[postSorting];

const postList = await getFetch<PostInfo[]>(
`/posts?status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`
);
if (categoryId) {
return `/posts?categoryId=${categoryId}&status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`;
}

return `/posts?status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에 if문 return값과 중복되는 url 코드는 분리해도 되겠네요!
const OPTION_URL=&sorting=${requestedSorting}&pages=${pageNumber};

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래와 같이 수정해보았습니다~

export const getPostListUrl = ({
  categoryId,
  postStatus,
  postSorting,
  pageNumber,
}: PostListByOption) => {
  const requestedStatus = REQUEST_STATUS_OPTION[postStatus];
  const requestedSorting = REQUEST_SORTING_OPTION[postSorting];

  const OPTION_URL = `status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`;

  if (categoryId) {
    return `/posts?categoryId=${categoryId}&${OPTION_URL}`;
  }

  return `/posts?${OPTION_URL}`;
};

};

export const getPostList = async ({
postStatus,
postSorting,
pageNumber,
categoryId,
}: PostListByOption) => {
const postListUrl = getPostListUrl({ pageNumber, postSorting, postStatus, categoryId });

const postList = await getFetch<PostInfo[]>(postListUrl);

return {
pageNumber,
postList,
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/components/post/PostList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Skeleton from '@components/common/Skeleton';
import { SORTING_OPTION, STATUS_OPTION } from '@components/post/PostListPage/constants';
import type { PostSorting, PostStatus } from '@components/post/PostListPage/types';

import { CATEGORY_ID } from '@constants/post';

import * as S from './style';

export default function PostList() {
Expand All @@ -23,9 +25,14 @@ export default function PostList() {
const { selectedOption: selectedSortingOption, handleOptionChange: handleSortingOptionChange } =
useSelect<PostSorting>('latest');

const URL = new URLSearchParams(window.location.search);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react-router 가 제공하는 useSearchParams 로 categoryId값을 가져오지 않는 이유가 있으신가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 기능이 있는지 몰랐어요 알려주셔서 감사합니다 제로 🔥🔥🔥

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이해가 부족해 여쭤보려고 남깁니다!
지금 로직상으로는 url에서 ?이하의 주소를 url로 저장을 하고, 이 중 categoryId를 가지고 와서 이걸 가지고 postList를 가지고 오는 것 같은데 맞을까요? 저희가 아직 카테고리에 대한 라우터는 정하지 않았던 거 같은데, 해당 url이 어떤 형태일지 잘 모르겠어요. 이런 경우 api와 같은 url을 따라가나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순히 /?categoryId=1와 같이 api를 따라서 생각했는데요. 사용자들에게 보여줄때는 /posts/category/1 이런식으로도 보여줄 수 있어서 내일 같이 의논해보면 좋겠어요 👍👍👍


const categoryId = URL.get(CATEGORY_ID);

const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = usePostList({
postSorting: selectedSortingOption,
postStatus: selectedStatusOption,
categoryId: Number(categoryId),
});

useEffect(() => {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/constants/post.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const POST = {
NOT_VOTE: 0,
};

export const CATEGORY_ID = 'categoryId';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 부분을 상수화한 이유가 궁금합니다!
제 생각으로는 api에서 categoryId라고 변수? 변경점 이름을 붙였고, 그것을 기반으로 url을 유추하셔서 로직을 구성하신 것 같아요!
그렇다면 해당 상수는 api와 깊은 관련이 있다고 생각이 드는데, api가 변경되지 않는다면 해당 상수도 변경될 가능성이 극히 적으니 상수화를 하지 않아도 될 것 같다는 생각이 들어요!
이건 제 추측이고, 라우팅할 url을 어떻게 설정할지에 따라 충분히 상수로 빼야 할 부분이라고도 생각이 드네요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 수아의 말처럼 api를 기반으로 url을 유추해서 로직을 구성했습니다.

단순히 제가 오타를 낼까봐 만든 상수였기에 사용되는 PostList 컴포넌트 폴더의 constants 파일로 옮기겠습니다 😵😵😵

8 changes: 5 additions & 3 deletions frontend/src/hooks/query/usePostList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import { PostSorting, PostStatus } from '@components/post/PostListPage/types';
interface UsePostList {
postSorting: PostSorting;
postStatus: PostStatus;
categoryId?: number;
}

const MAX_LIST_LENGTH = 10;

export const usePostList = ({ postSorting, postStatus }: UsePostList) => {
export const usePostList = ({ postSorting, postStatus, categoryId }: UsePostList) => {
const { data, error, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery<PostList>(
['posts', postSorting, postStatus],
({ pageParam = 0 }) => getPostList({ postSorting, postStatus, pageNumber: pageParam }),
['posts', postSorting, postStatus, categoryId],
({ pageParam = 0 }) =>
getPostList({ postSorting, postStatus, pageNumber: pageParam, categoryId }),
{
getNextPageParam: lastPage => {
if (lastPage.postList.length !== MAX_LIST_LENGTH) return;
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { example } from './example/get';

import { mockVoteResult } from './getVoteDetail';
import { mockPost } from './post';
import { mockVote } from './vote';
import { mockPostList } from './wus/post';

export const handlers = [...example, ...mockPost, ...mockVoteResult, ...mockVote];
export const handlers = [...example, ...mockPost, ...mockVoteResult, ...mockVote, ...mockPostList];
2 changes: 1 addition & 1 deletion frontend/src/mocks/wus/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { rest } from 'msw';

import { MOCK_POST_LIST } from '@mocks/mockData/postList';

export const postListHandlers = [
export const mockPostList = [
rest.get('/posts', (req, res, ctx) => {
const pages = Number(req.url.searchParams.get('pages'));

Expand Down