Skip to content

프론트엔드 코드 스타일 가이드

kwannee edited this page Nov 21, 2022 · 2 revisions

React/JSX Style Guide

컴포넌트 선언

  • 컴포넌트는 화살표 함수로 선언합니다.

    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 {...}

Typescript

Model

  • 모델은 interface로 정의합니다.

    // BAD
    type Ability = { ... }
    
    // GOOD
    interface Ability { ... }
  • 해당 모델의 RequestResponseinterface로 함께 정의합니다.

    // models/Ability.ts
    export interface StudyLogWithAbilityRequest {
      id: number;
      abilities: string[];
    }
    
    export interface StudyLogWithAbilityResponse {
      id: number;
      abilities: Ability[];
    }
  • 정의한 모델은 src/models에 도메인 별로 정리합니다.


React-Query

  • 프롤로그에서는 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;
    };

이유

  1. 커스텀 훅으로 분리한 이유?
    1. 비동기 호출을 담당하는 레이어를 나눠서 api 명세 변경에 유연하게 대처하기 위함입니다.
  2. fetcher를 분리한 이유?
    1. 현재는 react-query를 사용하고 있지만 이것은 추후에 변경이 될 수도 있기 때문에 미리 결합을 끊어 놓기 위함입니다.
Clone this wiki locally