-
Notifications
You must be signed in to change notification settings - Fork 77
[7팀 제정원] Chapter 2-3. 관심사 분리와 폴더구조 #66
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: main
Are you sure you want to change the base?
Changes from all commits
aa3d78a
21a2802
0e1163e
bb205f6
e1ae13a
c091586
b00c4e6
c5be0a6
e8ebff7
93ab481
62057ca
ba4fb13
5f4c127
294c67e
26c334b
9d90621
62a4811
ed443c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { Post } from "@/entities/posts/model/post.type" | ||
|
|
||
| export const addPost = async (newPost: Pick<Post, "title" | "body" | "userId">) => { | ||
| const res = await fetch("/api/posts/add", { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify(newPost), | ||
| }) | ||
| return res.json() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export const deletePost = async (postId: number) => { | ||
| const res = await fetch(`/api/posts/${postId}`, { | ||
| method: "DELETE", | ||
| }) | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getPosts = async () => { | ||
| const res = await fetch(`/api/posts`) | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| // export const getPostsByPagination = async (limit: number, page: number) => { | ||
| // const res = await fetch(`/api/posts?limit=${limit}&page=${page}`) | ||
| // return res.json() | ||
| // } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getPostsByTag = async (tag: string) => { | ||
| const res = await fetch(`/api/posts/tags/${tag}`) | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getPostsSearchQuery = async (searchQuery: string) => { | ||
| const res = await fetch(`/api/posts/search?query=${searchQuery}`) | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getTags = async () => { | ||
| const res = await fetch("/api/posts/tags") | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getUniqueTag = async (tag: string) => { | ||
| const res = await fetch(`/api/posts/tags/${tag}`) | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { Post } from "@/entities/posts/model/post.type" | ||
|
|
||
| export const updatePost = async (selectedPost: Post) => { | ||
| const res = await fetch(`/api/posts/${selectedPost.id}`, { | ||
| method: "PUT", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify(selectedPost), | ||
| }) | ||
| if (res.ok) { | ||
| return { message: "ok" } | ||
| } | ||
| throw new Error("Failed to update post") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| export interface Post { | ||
| id: number | ||
| title: string | ||
| body: string | ||
| tags: Tag[] | ||
| reactions: Reaction | ||
| userId: number | ||
| } | ||
|
|
||
| export interface Reaction { | ||
| like: number | ||
| dislike: number | ||
| } | ||
| export interface Tag { | ||
| url: string | ||
| slug: string | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { useMutation } from "@tanstack/react-query" | ||
| import { addPost } from "@/entities/posts/api/addPost" | ||
|
|
||
| export const useAddPostsMutation = () => { | ||
| return useMutation({ | ||
| mutationFn: addPost, | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { useQuery } from "@tanstack/react-query" | ||
| import { getPosts } from "@/entities/posts/api/getPosts" | ||
| import { Post } from "@/entities/posts/model/post.type" | ||
|
|
||
| interface PostsResponse { | ||
| posts: Post[] | ||
| total: number | ||
| skip: number | ||
| limit: number | ||
| } | ||
|
|
||
| export const usePostsQuery = () => { | ||
| return useQuery<PostsResponse>({ | ||
| queryKey: ["posts"], | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TanStack Query를 사용하면서 쿼리 키 관리가 번거롭게 느껴질 때가 있는데, 이 문제를 좀 더 쉽게 해결할 수 있도록 도와주는 query-key-factory 라이브러리가 있다고 합니다! TanStack Query에 관심이 있으시면 같이 살펴보시면 좋을 것 같아요! |
||
| queryFn: getPosts, | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import { create } from "zustand" | ||
|
|
||
| interface PostsStoreState { | ||
| posts: Post[] | ||
| total: number | ||
| skip: number | ||
| limit: number | ||
| setPosts: (posts: Post[]) => void | ||
| setTotal: (total: number) => void | ||
| setSkip: (skip: number) => void | ||
| setLimit: (limit: number) => void | ||
| } | ||
|
|
||
| export const usePostsStore = create<PostsStoreState>((set) => ({ | ||
| posts: [], | ||
| total: 0, | ||
| skip: 0, | ||
| limit: 10, | ||
| setPosts: (posts) => set((prev) => ({ ...prev, posts })), | ||
| setTotal: (total) => set((prev) => ({ ...prev, total })), | ||
| setSkip: (skip) => set((prev) => ({ ...prev, skip })), | ||
| setLimit: (limit) => set((prev) => ({ ...prev, limit })), | ||
| })) | ||
|
|
||
| /* | ||
| { | ||
| "posts": [ | ||
| { | ||
| "id": 1, | ||
| "title": "His mother had always taught him", | ||
| "body": "His mother had always taught him not to ever think of himself as better than others. He'd tried to live by this motto. He never looked down on those who were less fortunate or who had less money than him. But the stupidity of the group of people he was talking to made him change his mind.", | ||
| "tags": [ | ||
| "history", | ||
| "american", | ||
| "crime" | ||
| ], | ||
| "reactions": { | ||
| "likes": 192, | ||
| "dislikes": 25 | ||
| }, | ||
| "views": 305, | ||
| "userId": 121 | ||
| }, | ||
| {...}, | ||
| {...} | ||
| // 30 items | ||
| ], | ||
| "total": 251, | ||
| "skip": 0, | ||
| "limit": 30 | ||
| } | ||
| */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { Post } from "@/entities/posts/model/post.type" | ||
| import { useAllPostsQuery } from "@/entities/posts/model/useAllPostsQuery" | ||
| import { useAllUsersQuery } from "@/entities/users/model/useAllUsersQuery" | ||
|
|
||
| export const usePostsWithUsers = (limit: number, skip: number) => { | ||
| const postsQuery = useAllPostsQuery(limit, skip) | ||
| const usersQuery = useAllUsersQuery() | ||
|
|
||
| const isLoading = postsQuery.isLoading || usersQuery.isLoading | ||
| const isError = postsQuery.isError || usersQuery.isError | ||
|
|
||
| // TODO: 데이터 조합 따로 함수로 분리 | ||
| let posts: Post[] = [] | ||
| if (postsQuery.data && usersQuery.data) { | ||
| posts = postsQuery.data.posts.map((post) => ({ | ||
| ...post, | ||
| author: usersQuery.data.users.find((user) => user.id === post.userId), | ||
| })) | ||
| } | ||
|
|
||
| return { | ||
| posts, | ||
| total: postsQuery.data?.total ?? 0, | ||
| isLoading, | ||
| isError, | ||
| error: postsQuery.error || usersQuery.error, | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { useQuery } from "@tanstack/react-query" | ||
| import { getTags } from "@/entities/posts/api/getTags" | ||
|
|
||
| export const useTagsList = () => { | ||
| return useQuery({ | ||
| queryKey: ["tags"], | ||
| queryFn: getTags, | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { useQuery } from "@tanstack/react-query" | ||
| import { getUniqueTag } from "@/entities/posts/api/getUniqueTag" | ||
|
|
||
| export const useUniqueTag = (tag: string) => { | ||
| return useQuery({ | ||
| queryKey: ["tags", tag], | ||
| queryFn: () => getUniqueTag(tag), | ||
| enabled: !!tag, | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getUniqueUser = async (userId: number) => { | ||
| const res = await fetch(`/api/users/${userId}`) | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export const getUsers = async () => { | ||
| const res = await fetch("/api/users?limit=0&select=username,image") | ||
| return res.json() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { useQuery } from "@tanstack/react-query" | ||
| import { getUniqueUser } from "@/entities/users/api/getUniqueUser" | ||
| import { User } from "@/entities/users/model/user.type" | ||
|
|
||
| export const useUniqueUserQuery = (userId: number) => { | ||
| return useQuery<User>({ | ||
| queryKey: ["user", userId], | ||
| queryFn: () => getUniqueUser(userId), | ||
| enabled: !!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.
Pick이라는 기능이 있군요.. TypeScript를 잘 몰라서 이런 기능 있었으면 했는데..