π Links
PostMobism μ BE Apiλ₯Ό νμ©νμ¬ νμκ°μ , λ‘κ·ΈμΈ, κ²μκΈ CRUD κ·Έλ¦¬κ³ λκΈ μμ±μ ν μ μλ μ¬μ΄νΈμ λλ€
μ΄ 2λͺ
μ΄ μ°Έμ¬νμκ³ , μ€ μ°ν΄ κΈ°κ° μ μΈ 2024-02-03 ~ 2024-02-17 μ½ 12μΌ λμ μ§ννμμ΅λλ€
νμλ λ°°ν¬ λ° μμν μ€λ₯ μμ λ° λ¦¬ν©ν λ§μ μ§ννμμ΅λλ€
β ν¨μ¨λ³΄λ€λ "λ§μ κ²μ μ»μ΄κ°λ κ²" μ μ΄μ μ λ§μΆ μν λΆλ΄
μ΄μ μ μ§ννλ©΄μ μμ¬μ λ κ²λ€μ μ΄λ²μ μ λλ‘ μ±κΈ°λ κ²μ΄ λͺ©νμκΈ° λλ¬Έμ,
μ΄μ μλ λ³΄ν΅ λ‘μ§μ΄ κ²ΉμΉκΈ°μ ν μ¬λμ΄ νμκ°μ
/λ‘κ·ΈμΈμ λͺ¨λ μ§ννλ€λ©΄ μ΄λ²μλ κ·Έ μμμ λλ μ μ§ννμμ΅λλ€
ex) you: νμκ°μ
/ν¬μ€νΈ, me: λ‘κ·ΈμΈ/λκΈ
μ΄λ μλ‘ ν¨μλͺ μ΄λ ν΄λλͺ λ± λ‘μ§μ΄ κ²ΉμΉμΉκ±°λ νΌλμ΄ μ¬ μ μμ΄μ PR reviewλ₯Ό κΌΌκΌΌνκ² μ§ννκΈ°λ‘ νμ΅λλ€
Login, Comment, postDetailModal
μλ νμλΆκ»μ λ°±μλ ApiλΆμμ μνμ€ λ€μ΄μ΄κ·Έλ¨μ λλ€
λΆμμ΄ μ²μμ΄λΌ μ΄λ»κ² ν΄μΌν μ§ λͺ¨λ₯΄κ² μ΄μ κ·Έλ₯ μκ°μ μ 리νλ―μ΄ ν΄κ°λλ°,
νμλΆ λλΆμ μνμ€ λ€μ΄μ΄κ·Έλ¨μ λν΄μ μκ²λμ΄ ν¨κ» λ€μ μ 리νμ΅λλ€!
μν κ² κ°μ§λ§, λΉ μ§ κ²μ΄ μλ€λ©΄ Thunder Clientλ‘ μ€μ νμ©ν dataμ μΈν μμν κ°μ μ λλ‘ μ°μνμ§ λͺ»νμ΅λλ€
λ°±μλ API λΆμμ μμμΌλ‘λ§ μ§ννλ€ λ³΄λ, μ€μ§μ μΌλ‘ ꡬνν λ μμλλ‘ λμ§ μμλ λΆλΆλ€μ΄ μμμ΅λλ€
λν Api λΆμ, μνμ€ λ€μ΄μ΄κ·Έλ¨ 그리기, νΌκ·Έλ§ λͺ¨λ μ΅μνμ§ μλ€λ³΄λ ν¨μ¨μ μΈ μ§νμ΄ μ λμ§ μμλ κ±° κ°μ΅λλ€
β‘οΈ SignUp/In
β‘οΈ postPost
β‘οΈ getPost
β‘οΈ patchPost
β‘οΈ deletePost
β‘οΈ getPostDetail
β‘οΈ postComment
β‘οΈ getComment
draw.io (무λ£)
ThunderClientλ‘ λΆμν κ²μ λ°νμΌλ‘ μμ² μ€ν¨μ μ±κ³΅μ κ°μ λλ μ λμ¬ μ μλ λ²κ·Έλ€μ λν΄ μμΈ‘νμ΅λλ€
μΌμͺ½μλ λΆνμν μμ²μ΄λ ν ν° μΈν
λ±μ λν μμΈ λ΄μ©λ€μ μ΄λ»κ² μ²λ¦¬ν μ§ μμν΄λ³΄μμ΅λλ€
νμ μ chap-chap νλ‘μ νΈμμ μ΄κ³Ό μ±μ λ€νλλ§νΌ, κ·Έ λ νλ κ²λ€μ λ°νμΌλ‘ μ μ§ννμμ΅λλ€.
π€ 리λμ΄
π€ GitHub Issue
π€ PR Review
π€ PR Template
comment.slice.ts
import { TCommentsResponse } from "@/type/type"
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import { CommentApi } from "./comment.api"
import { CommentDataType } from "@/pages/main/components/post-detail-modal/components/comment/comment-form"
type CommentState = {
commentList: TCommentsResponse | null
loading: boolean
error: string | null
}
const initialState: CommentState = {
commentList: {
data: [],
pageNation: undefined,
},
loading: false,
error: "",
}
// getComments : read
export const getComments = createAsyncThunk<TCommentsResponse, { page: number; postId: string }>(
"comment/getComments",
async ({ page, postId }) => {
try {
const posts = await CommentApi.getComment({ page, postId })
return posts
} catch (error) {
throw new Error("κ²μκΈ λ°μ΄ν°λ₯Ό λΆλ¬μ€λ λ° μ€ν¨νμ΅λλ€!")
}
},
)
export const postComment = createAsyncThunk("comment/postComment", async ({ parentId, content }: CommentDataType) => {
try {
const commentData = { parentId, content }
const res = await CommentApi.postComment(commentData)
return res.data
} catch (error) {
throw new Error("λκΈ μμ±μ μ€ν¨νμμ΅λλ€")
}
})
//Reducerμ action μ μ
export const commentSlice = createSlice({
name: "comment",
initialState,
reducers: {},
//extraReducersλ₯Ό μ¬μ©νμ¬ λΉλκΈ° μ‘μ
(getPosts)μ μ±κ³΅, μ€ν¨ λ° λ³΄λ₯ μνμ λ°λΌ μνλ₯Ό μ
λ°μ΄νΈ
extraReducers(builder) {
builder
// getPost : read
.addCase(getComments.pending, state => {
state.loading = true
})
.addCase(getComments.fulfilled, (state, action) => {
state.loading = false
state.error = null
state.commentList = {
data: state.commentList?.data.concat(action.payload.data)!,
pageNation: action.payload.pageNation,
}
})
.addCase(getComments.rejected, (state, action) => {
state.loading = false
state.error = action.error.message || "μκΈ°μΉ λͺ»ν μλ¬λ‘ κ²μκΈ λ°μ΄ν°λ₯Ό λΆλ¬μ€μ§ λͺ»νμ΅λλ€!"
state.commentList = null
})
// postComment: create
.addCase(postComment.pending, state => {
state.loading = true
})
.addCase(postComment.fulfilled, (state, action) => {
state.loading = false
})
.addCase(postComment.rejected, (state, action) => {
state.loading = false
state.error = action.error.message || "λκΈ μμ±μ μ€ν¨νμμ΅λλ€"
})
},
})
// export const { setPostList } = postSlice.actions
export default commentSlice.reducer
store.ts
import userReducer from "@/features/user/user.slice"
import postReducer from "@/features/post/post.slice"
import commentReducer from "@/features/comment/comment.slice"
import { configureStore } from "@reduxjs/toolkit"
import { commentApi } from "@/hooks/use-get-comment-list-query"
export const store = configureStore({
reducer: {
user: userReducer,
post: postReducer,
comment: commentReducer,
[commentApi.reducerPath]: commentApi.reducer,
},
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: false, // λΆνμν κ²½κ³ λ₯Ό νΌνκΈ° μν΄ μΆκ°
}).concat(commentApi.middleware),
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
RTK Query μ΄μ©ν 무νμ€ν¬λ‘€λ§ ꡬν
import { TCommentsResponse } from "@/type/type"
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"
const token = localStorage.getItem("access_token")
export const commentApi = createApi({
reducerPath: "commentApi",
baseQuery: fetchBaseQuery({
baseUrl: import.meta.env.VITE_BACKEND_URL,
headers: {
authorization: `Bearer ${token}`,
},
credentials: "include",
}),
tagTypes: ["Comment"],
endpoints: builder => ({
getCommentList: builder.query<TCommentsResponse, { postId: string; pageParam: number }>({
query: ({ postId, pageParam }) => ({
url: `/data/comment?parentId=${postId}&page=${pageParam}&apiKey=${import.meta.env.VITE_API_KEY}&pair=${import.meta.env.VITE_PAIR}`,
method: "GET",
}),
providesTags: ["Comment"],
serializeQueryArgs: ({ queryArgs }) => {
const newQueryArgs = { ...queryArgs }
if (newQueryArgs.pageParam) {
newQueryArgs.pageParam = 0
}
return newQueryArgs
},
merge: (currentCacheData, responseData) => {
if (currentCacheData.data) {
return {
...currentCacheData,
...responseData,
data: [...currentCacheData.data, ...responseData.data],
}
}
},
}),
}),
})
export const { useGetCommentListQuery } = commentApi
μμ μ΄λλ‘ thunder client, draw.ioλ₯Ό ν΅ν΄ 극볡!
곡μλ¬Έμλ₯Ό μ½μ΄λ΄λ λ§μ΄ μ΄λ €μ μ΅λλ€..
λ¨μ 리ν©ν λ§μ μ§ννλ©° λ€μν λ² μ λμ§ μμλ λΆλΆμ λ³΄κ³ μ 리ν κ²μ λλ€
μ μ μν κ΄λ¦¬μ 무ν μ€ν¬λ‘€λ§μ react-query, useInfiniteQueryλ₯Ό μ¬μ©νλ κ²μ΄ μ΄λ¨κΉ..^^
νμ
μ€ν¬λ¦½νΈ, RTK, λ°±μλ APIλΆμμ μν νλ‘μ νΈμλ κ±° κ°μ΅λλ€
μμ§ μ΄λ ΅κΈ΄νμ§λ§ κ·Έλλ μ μ μ΅μν΄μ Έκ°λ κ² λκ»΄μ‘μ΅λλ€
λ€ μ²μν λλ μ΄λ ΅μ§λ§, ν λ² νκ³ λ€μμ λ μ¬μ©νλ©΄ κ·Έλλ μ΅μν΄μ§λ€λ κ²μ μκ²λμ΄ μλ‘μ΄ Library λ° Toolμ λν λλ €μμ΄ μ’ μ¬λΌμ‘μ΅λλ€
λ°±μλ API λΆμμ μ무λλ μμ§ λ°±μλμμ νμ
κ²½νμ΄ λͺ¨μλΌλ€λ³΄λ μ΄μ© μ μλ λΆλΆμ΄κΈ΄ νμ§λ§, ThunderClient + μνμ€ λ€μ΄μ΄κ·Έλ¨ + κ°λ°μ λꡬ κ²μ¬ μ°½
μ μ΅μν΄μ Έμ λΆμ‘±ν¨μ λ©κΏλκ°μΌκ² μ΅λλ€!
νΉν μ΄λ² νλ‘μ νΈ λ μμμΉ λͺ»νκ² μνκ³ , λ μ°ν΄κ° λΌλ©΄μ νλ‘μ νΈκ° μ‘°κΈ λ°λ¦¬λ μΌμ΄ μμλλ° μ»¨λμ κ±΄κ° κ΄λ¦¬λ₯Ό μνκ³ ... κ³νμ νλ‘μ νΈμ μ°¨μ§μ΄ μλλ‘ μΈμμ λ μ± μκ°μκ² μν΄μΌκ² λ€λ μκ°μ΄ λ€μμ΅λλ€.