Skip to content

[8팀 조건호] Chapter 2-3. 관심사 분리와 폴더구조#57

Open
alchogh wants to merge 8 commits intohanghae-plus:mainfrom
alchogh:main
Open

[8팀 조건호] Chapter 2-3. 관심사 분리와 폴더구조#57
alchogh wants to merge 8 commits intohanghae-plus:mainfrom
alchogh:main

Conversation

@alchogh
Copy link

@alchogh alchogh commented May 1, 2025

과제 체크포인트

기본과제

목표 : 전역상태관리를 이용한 적절한 분리와 계층에 대한 이해를 통한 FSD 폴더 구조 적용하기

  • 전역상태관리를 사용해서 상태를 분리하고 관리하는 방법에 대한 이해
  • Context API, Jotai, Zustand 등 상태관리 라이브러리 사용하기
  • FSD(Feature-Sliced Design)에 대한 이해
  • FSD를 통한 관심사의 분리에 대한 이해
  • 단일책임과 역할이란 무엇인가?
  • 관심사를 하나만 가지고 있는가?
  • 어디에 무엇을 넣어야 하는가?

체크포인트

  • 전역상태관리를 사용해서 상태를 분리하고 관리했나요?
  • Props Drilling을 최소화했나요?
  • shared 공통 컴포넌트를 분리했나요?
  • shared 공통 로직을 분리했나요?
  • entities를 중심으로 type을 정의하고 model을 분리했나요?
  • entities를 중심으로 ui를 분리했나요?
  • entities를 중심으로 api를 분리했나요?
  • feature를 중심으로 사용자행동(이벤트 처리)를 분리했나요?
  • feature를 중심으로 ui를 분리했나요?
  • feature를 중심으로 api를 분리했나요?
  • widget을 중심으로 데이터를 재사용가능한 형태로 분리했나요?

심화과제

목표: 서버상태관리 도구인 TanstackQuery를 이용하여 비동기코드를 선언적인 함수형 프로그래밍으로 작성하기

  • TanstackQuery의 사용법에 대한 이해
  • TanstackQuery를 이용한 비동기 코드 작성에 대한 이해
  • 비동기 코드를 선언적인 함수형 프로그래밍으로 작성하는 방법에 대한 이해

체크포인트

  • 모든 API 호출이 TanStack Query의 useQuery와 useMutation으로 대체되었는가?
  • 쿼리 키가 적절히 설정되었는가?
  • fetch와 useState가 아닌 선언적인 함수형 프로그래밍이 적절히 적용되었는가?
  • 캐싱과 리프레시 전략이 올바르게 구현되었는가?

과제 셀프회고

과제에서 좋았던 부분

현업에서 tanstack-query로 관리하는 데이터를 zustand로 또 관리해서 이 부분을 바꾸기 위해서 리팩토링을 진행하려고 하는데 좋은 연습이 되었다. FSD 구조로 공부를 하게 되니까 자연스럽게 선언형 프로그레밍, 클린코드 등등 공부하고 고민하게 되는 계기가 되었다. 그리고 개발자로써 어떤식으로 코드를 짜야하는지 방향성이 잡히게 되는 과제였다.

과제를 하면서 새롭게 알게된 점

FSD 구조와 전반적인 클린 아키텍쳐에 대해서알게 되었다.

과제를 진행하면서 아직 애매하게 잘 모르겠다 하는 점, 혹은 뭔가 잘 안되서 아쉬운 것들

스웨거 같은 문서가 없어서 구조를 잘 짜는 것보다 타입을 지정하는데 시간을 더 많이 쓰게 되었다.

리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문

  • 혹시 tanstack-query로 데이터를 가져와서 zustand로 관리하는 경우가 있을까요? 아무리 봐도 전사람이 왜 이렇게 짜놓은지 이해가 가지 않아서 놓친 부분이 있나 싶어 질문합니다.
  • react-> next.js 로 마이그레이션인데 tanstack-query는 클라이언트 라이브러린데 그럼 데이터를 가져오는 부분은 클라이언트 컴포넌트로 만들어야하나요? 예를 들어 route.ts에서 api를 선언하고, useHooks에서 tanstack-query를 사용해서 route.ts에서 작성한 api를 끌어와 클라이언트 컴포넌트에서 끌어와 쓰기. 제 기준에서는 route.ts(POST) 와 action.ts(submitHandler)정도로 알고있는데 혹시 이 부분에 대해서 공부할 레퍼런스가 있을까요?

Comment on lines +2 to +3
import { CommentsAPI } from "../../../5_entities/comment/model/api"
import { Comment } from "../../../5_entities/comment/model/type"
Copy link
Member

Choose a reason for hiding this comment

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

alias 쓰면 좋아보입니다!!

}

export const usePostFilterStore = create<PostFilterState>()(
persist(
Copy link
Member

Choose a reason for hiding this comment

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

오 .. persist 사용해서 전역상태 관리하셨군요
너무 좋은것 같습니다!!

Comment on lines +5 to +100
export const postAPI = {
getPosts: async (params: { limit: number; skip: number }): Promise<PostListResponse> => {
const response = await fetch(`/api/posts?limit=${params.limit}&skip=${params.skip}`)
const data = await response.json()
return data
},

// 게시물 추가
addPost: async (post: NewPost): Promise<Post> => {
const response = await fetch("/api/posts/add", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(post),
})
const data = await response.json()
console.log(data)
return data
},

// 게시물 검색
searchPosts: async (searchQuery: string): Promise<PostListResponse> => {
const response = await fetch(`/api/posts/search?q=${searchQuery}`)
const data = await response.json()
return data
},

// 게시물 태그 검색
searchPostsByTag: async (tag: string): Promise<PostListResponse> => {
const response = await fetch(`/api/posts/search?tag=${tag}`)
const data = await response.json()
return data
},

// 게시물 업데이트
updatePost: async (post: Post): Promise<Post> => {
const response = await fetch(`/api/posts/${post.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(post),
})
const data = await response.json()
return data
},

// 게시물 삭제
deletePost: async (id: number): Promise<void> => {
await fetch(`/api/posts/${id}`, {
method: "DELETE",
})
},

getPostsWithAuthors: async ({ limit, skip }: { limit: number; skip: number }) => {
// 게시물 가져오기
const postsData = await postAPI.getPosts({ limit, skip })

if (postsData.posts.length === 0) {
return {
posts: [],
total: postsData.total,
}
}
// 사용자 가져오기
const usersData = await userAPI.getUsers({ limit: 0, skip: 0 })

const postsWithUsers: Post[] = postsData.posts.map((post) => {
const author = usersData.users.find((user) => user.id === post.userId)
if (!author) throw new Error(`User not found for userId: ${post.userId}`)
return { ...post, author }
})

return {
posts: postsWithUsers,
total: postsData.total,
}
},

getPostsByTag: async (tag: string): Promise<{ posts: Post[]; total: number }> => {
const [postsRes, usersRes] = await Promise.all([
fetch(`/api/posts/tag/${tag}`),
fetch(`/api/users?limit=0&select=username,image`),
])

const postsData = await postsRes.json()
const usersData = await usersRes.json()

const postsWithUsers = postsData.posts.map((post: Post) => ({
...post,
author: usersData.users.find((user: User) => user.id === post.userId),
}))

return {
posts: postsWithUsers,
total: postsData.total,
}
},
}
Copy link
Member

Choose a reason for hiding this comment

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

제 리뷰에 남겨주신 피드백 내용처럼 작성해주셨네요!
저도 이 방식 참고하겠습니다!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants