
어제까지해서 관심사를 모두 분리하고 남은 page 코드입니다. props를 완전히 없앴으며, view만 있는 item 정도만 받아서 수행하는 것으로 변경했습니다.
import { PostsHeader } from "@/features/posts/ui/PostsHeader";
import { PostsPagination } from "@/features/posts/ui/PostsPagination";
import { PostsSearchHeader } from "@/features/posts/ui/PostsSearchHeader";
import { PostsTable } from "@/features/posts/ui/PostsTable";
import { PostsDialogs } from "@/widgets/posts/ui/PostsDialogs";
import { Card, CardContent, CardHeader } from "../shared/ui";
const PostsManager = () => {
return (
<Card className="w-full max-w-6xl mx-auto">
<CardHeader>
<PostsHeader />
</CardHeader>
<CardContent>
<div className="flex flex-col gap-4">
<PostsSearchHeader />
<PostsTable />
<PostsPagination />
</div>
</CardContent>
<PostsDialogs />
</Card>
);
};
export default PostsManager;
회사에서 자주 사용하던 패턴인데, URL을 구성하는 Path들을 모두 상수 단어화 하여 사용하는 방식으로 변경해봤습니다. 이렇게 만들었던 이유는 정해진 단어에 대하여 확실하게 오타를 배제하고 사용할 수 있도록 할 수 있기 때문이었습니다.
import { Comment } from "@/entities/comment/models/comment.types";
import { Post } from "@/entities/post/models";
import { User } from "@/entities/user/models/user.types";
// SEGMENTS
const _API = "api";
const _ADD = "add";
const _POSTS = "posts";
const _COMMENTS = "comments";
const _USERS = "users";
const _TAG = "tag";
const _TAGS = "tags";
const _SEARCH = "search";
const _POST = "post";
// URL
export const API_URL = {
// posts
POSTS: (limit: number, skip: number) => `/${_API}/${_POSTS}?limit=${limit}&skip=${skip}` as const,
POSTS_ID: (id: Post["id"]) => `/${_API}/${_POSTS}/${id}` as const,
POSTS_ADD: `/${_API}/${_POSTS}/${_ADD}`,
POSTS_TAG: (tag: Post["tags"][number]) => `/${_API}/${_POSTS}/${_TAG}/${tag}` as const,
POSTS_TAGS: `/${_API}/${_POSTS}/${_TAGS}`,
POSTS_SEARCH: (query: string) => `/${_API}/${_POSTS}/${_SEARCH}?q=${query}` as const,
// comments
COMMENTS_ID: (id: Comment["id"]) => `/${_API}/${_COMMENTS}/${id}` as const,
COMMENTS_ADD: `/${_API}/${_COMMENTS}/${_ADD}`,
COMMENTS_POST_ID: (id: Post["id"]) => `/${_API}/${_COMMENTS}/${_POST}/${id}` as const,
// users
USERS: `/${_API}/${_USERS}?limit=0&select=username,image`,
USERS_ID: (id: User["id"]) => `/${_API}/${_USERS}/${id}` as const,
} as const;
사용하는 쪽은 URL을 함수처럼 사용하도록 typescript 를 통해 const로 선언하여 고정된 문자열이 반환됨을 확정하여 오류가 없도록 구현하였습니다.
import { API_URL } from "@/shared/lib/api-path";
import { Post, PostsData, UsersData } from "../models";
export const fetchPostsAPI = async (limit: number, skip: number) => {
const response = await fetch(API_URL.POSTS(limit, skip));
const postsData = (await response.json()) as PostsData;
const response2 = await fetch(API_URL.USERS);
const usersData = (await response2.json()) as UsersData;
const posts: Post[] = postsData.posts.map((post) => {
const author = usersData.users.find((user) => user.id === post.userId);
if (!author) throw new Error("wrong author");
return { ...post, author };
});
return { posts, total: postsData.total };
};
아직 파일을 분리하고, 함수와 API를 나누는 정도의 작업이 완료된 상태인데, 현재까지만 하고 심화과제를 진행하는 방향으로 진행할 것 같습니다.