-
Notifications
You must be signed in to change notification settings - Fork 28
프론트엔드 코드 스타일 가이드
kwannee edited this page Nov 21, 2022
·
2 revisions
컴포넌트 선언
-
컴포넌트는 화살표 함수로 선언합니다.
const App = () => { return <div></div>; }; export default App;
Event Handler
-
컴포넌트의 prop으로 넘기는 이벤트 핸들러는
on
접두사를 붙입니다.// BAD <Editor title={title} handleChangeTitle={onChangeTitle} height="40vh" editorContentRef={editorContentRef} /> // GOOD <Editor title={title} onChangeTitle={onChangeTitle} height="40vh" editorContentRef={editorContentRef} />
Props Naming
-
Props의 타입 or interface는
컴포넌트명
+Props
로 해당 컴포넌트 최상단에 정의합니다.// BAD interface Props {...} // GOOD interface SidebarProps {...}
Model
-
모델은
interface
로 정의합니다.// BAD type Ability = { ... } // GOOD interface Ability { ... }
-
해당 모델의
Request
와Response
도interface
로 함께 정의합니다.// models/Ability.ts export interface StudyLogWithAbilityRequest { id: number; abilities: string[]; } export interface StudyLogWithAbilityResponse { id: number; abilities: Ability[]; }
-
정의한 모델은
src/models
에 도메인 별로 정리합니다.
-
프롤로그에서는 React-Query를 사용해 비동기 호출 로직을 관리합니다.
-
react-query는 역할에 맞는 이름을 가진 커스텀 훅으로 분리합니다.
// BAD useQuery(...) // 컴포넌트에서 바로 사용하는 경우 // GOOD const useGetComments = ( ... ) => useQuery( ... )
useQuery
-
get
메서드를 요청할 때는 useQuery를 사용합니다.// BAD const useGetComments = ( ... ) => useMutation(...) // GOOD const useGetComments = ( ... ) => useQuery( ... )
-
useGet
+자원
으로 네이밍을 통일합니다.// BAD export const useComments = (studylogId: number) => useQuery([QUERY_KEY.comments, studylogId], () => getComments(studylogId)); // GOOD export const useGetComments = (studylogId: number) => useQuery([QUERY_KEY.comments, studylogId], () => getComments(studylogId));
-
쿼리 키는 해당 파일 최상단에 객체 형태로 관리합니다.
const QUERY_KEY = { comments: 'comments', };
useMutation
-
post
,put
,delete
메서드에 useMutation을 사용합니다.// BAD const useEditComment= ( ... ) => useQuery( ... ); // PUT const useCreateComment = ( ... ) => useQuery( ... ); // POST const useEditComment= ( ... ) => useQuery( ... ); // DELETE // GOOD const useEditComment= ( ... ) => useMutation( ... ); // PUT const useCreateComment = ( ... ) => useMutation( ... ); // POST const useEditComment= ( ... ) => useMutation( ... ); // DELETE
-
method
에 맞게useEdit
,useCreate
,useDelete
로 네이밍을 통일합니다.const useEditComment= ( ... ) => useMutation( ... ); // PUT const useCreateComment = ( ... ) => useMutation( ... ); // POST const useEditComment= ( ... ) => useMutation( ... ); // DELETE
공통
-
useQuery와 useMutation의 fetcher는 따로 분리합니다.
// BAD export const useGetComments = (studylogId: number) => useQuery([QUERY_KEY.comments, studylogId], async (studylogId: number): Promise<CommentListResponse> => { const response = await client.get(`/studylogs/${studylogId}/comments`); return response.data; }); // GOOD export const useGetComments = (studylogId: number) => useQuery([QUERY_KEY.comments, studylogId], () => getComments(studylogId));
-
분리한 useQuery와 useMutation은 src/hooks/queries에 도메인 별로 관리합니다.
hooks ┗ queries ┣ auth.ts ┣ comment.ts ┣ filters.ts ┣ ... ┗ profile.ts
-
fetcher는 axios instance인
client
를 사용하여 따로 분리합니다.//BAD //GOOD const getComments = async (studylogId: number): Promise<CommentListResponse> => { const response = await client.get(`/studylogs/${studylogId}/comments`); return response.data; };
- 커스텀 훅으로 분리한 이유?
- 비동기 호출을 담당하는 레이어를 나눠서 api 명세 변경에 유연하게 대처하기 위함입니다.
- fetcher를 분리한 이유?
- 현재는 react-query를 사용하고 있지만 이것은 추후에 변경이 될 수도 있기 때문에 미리 결합을 끊어 놓기 위함입니다.