HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤎
프론트엔드 데브코스 5기 교육생
/
🦁
이희진팀
/
🤝
컨벤션
/
개발 컨벤션
개발 컨벤션
/
사프 컨벤션

사프 컨벤션

├─ app │  ├─ api │  ├─ main │  │ ├─ page.tsx │  │ └─ _components # 메인 페이지에서만 사용되는 컴포넌트 │  └─ mypage │   ├─ page.tsx │   └─ _components ├— page.tsx ├— layout.tsx ├— providers.tsx ├— globals.css ├— components # 여기는 공통 컴포넌트 ├─ hooks │ ├─ queries │ ├─ mutations │ └─ useTimeout.ts ├─ constants ├─ types ├─ utils / libs └─ public
  • 디렉토리 네이밍: 복수형
  • 파일 네이밍: 단수형
  • component 파일을 제외한 다른 파일 및 폴더들: kebab-case
 
  • (auth)
    • todo (투두 페이지)
      • page.tsx
    • article (아티클 페이지)
      • page.tsx
    • layout.tsx
  • page.tsx (랜딩 페이지)
  • layout.tsx

2. 개발 컨벤션

  1. 줄임말은 쓰지않는다. (ex. event => e)
  1. 함수 export 방식 선언과 동시에 export (e.g. export const useTimeout = () ⇒ { … })
  1. 페이지와 컴포넌트는 function 키워드를 사용해서 선언한다.
  1. 핸들러 함수는 컴포넌트 내부에서 선언을 하고 const 키워드를 사용한다.
  1. 🐞  핸들러를 제외한 계산식이 들어가는 함수 같은 경우는 컴포넌트 바깥에서 function 키워드를 사용하여 선언(코드리뷰를 통해 다시 컨벤션 확립하기)
컴포넌트를 제외한 함수 선언 방식은 const 를 사용합니다.
export default function ListItem() { const [age, setAge] = useState(100); const handleClick = () => { ... } return <div>asdf</div> } // 화살표 함수를 쓰지 않은 이유는 컨벤션 통일 function a() { ... }
  1. 세미콜론을 필수적으로 작성 (prettier로 관리)
  1. 리터럴 값은 상수로 만들어서 사용합니다. 상수는 Snake_Case를 사용합니다. ex) BASE_URL
  1. 변수명은 camelCase로 작성합니다.
  1. 라우트(폴더)명은 kebab-case를 사용합니다. ex) todo, user-info
  1. 컴포넌트명은 PascalCase를 사용합니다. ex) TodoList.tsx
  1. alias를 이용해서 파일 절대 경로로 import, export 사용합니다
    1. import a from './a'; ✅ 단일 레벨(뎁스)까지만 상대경로 가능 & 모두 동의 ✅
  1. export 할때 barrel export 방식을 사용하지 않습니다.
  1. 타입을 분리할 경우(여러 곳에서 타입이 생성될 경우(2군데 이상)) types 디렉토리에 관리한다.
      • 컴포넌트 Props → 컴포넌트에서
      • Request / Response type → route handler에 추가해서 사용
        • 그래서 api랑 가까웠음 좋겠다
        • api/schema → response / request type
        • api handler → response / request type
      ~/api/todo.ts fetch(https://baseurl/todo).then(res=>) ~/api/todo/route.ts ~~~ componets fetch(api/todo)
  1. 최대한 코드에 대한 설명 주석은 적지 않습니다. 이름만 읽어도 무슨 일을 하는 함수인지 알 수 있어야합니다.
  1. 이벤트 핸들러를 정의할때 handle + 이벤트명 + 대상로 정의합니다. ex. handleCopyLink
    1. handle + 이벤트명 + 대상 - Button - handler -> handleClickButton - Link - handler -> handleClickLink
  1. on 접두사가 붙은 경우, 이 Prop에 실제 이벤트가 연결되어 있다는 걸 뜻하고, handle 접두사가 붙은 경우, 이벤트가 발생했을 때 호출되는 실제 Function을 의미합니다.
    1. function DateTypeToggleButton ({ onClick }) { return <button onClick={onClick} /> } function ModalButton ({ onClick }) { return <button onClick={onClick} /> } function Calendar () { const handleClickDateType = () => {} const handleModalOpen = () => {} /* 주의!! 컴포넌트의 props로 핸들러를 넘길때도 handle 접두사를 사용해야 합니다. */ return ( <> <DateTypeToggleButton onClick={handleClickDateType} /> <ModalButton onClick={handleModalOpen} /> </> ) }
  1. 컴포넌트 props 지정 방식
    1. interface CommentListItemProps {...} const CommentListItem = ({ id, author, loginId, createdAt, comment, isMyComment }: CommentListItemProps) => { ... }
  1. 컴포넌트 props 네이밍
    1. interface Props { ... } const ListItem = () => {} const CommentListItem = ({ id, author, loginId, createdAt, comment, isMyComment }: CommentListItemProps) => { ... } interface CommentProps extends ComponentProps<typeof ListItem> { comment: string; } 다른 컴포넌트에서 Props를 전달받고 이걸 감싼 컴포넌트 - ComponentProps<typeof CommentListItem> - HTMLAttributes<HTMLInputElement>
  1. asset 파일(image, svg)은 케밥 케이스를 사용하여 네이밍합니다.(ex. erase-check.svg)
      • kebab-case