Skip to content

FE 팀 컨벤션

Yoonkyoung (빙봉) edited this page Sep 18, 2024 · 11 revisions

2024-momo FE 팀의 코드 컨벤션을 소개해요 :) 😊

목차

1. 🎁 컴포넌트

  1. 컴포넌트 생성 & export

  2. 컴포넌트 props

  3. 컴포넌트 내부 이벤트 (onClick, etc...)

2. 🪝 훅

3. 🆎 타입

  1. type vs interface

  2. Typescript 관련 기타 컨벤션

4. 🌊 상수

5. 📂 디렉토리 구조

6. 🎨 css

  1. css prop 변수 네이밍 규칙

7. 📞 apis

8. 🧚 상태 관리 라이브러리


🚀 프론트엔드 코드 컨벤션

🎁 컴포넌트

1) 컴포넌트 생성 & export

  • 컴포넌트의 경우 export default function을 수행해요.
  • 컴포넌트를 만듦과 동시에 export 할 수 있도록 해요.
export default function Component(){
  return <></>
}

2) 컴포넌트 props

컴포넌트가 받는 props의 타입을 정의할 때는

interface <컴포넌트이름>Props {
  //..
}

으로 정의해요. 그리고, 하나의 파일에서만 사용되는 타입 또는 인터페이스(TS 인터페이스)는 해당 파일에 작성해야함을 유의해요!

3) 컴포넌트 내부 이벤트 (onClick, etc...)

  1. 이벤트 핸들러 함수 콜 시그니쳐
  • 이벤트 핸들러 함수가 받는 이벤트 객체의 타입을 명시하고, react에서 import하는 방식을 사용해요.
import type { ChangeEvent } from 'react';

const doSomething = (e : ChangeEvent<HTMLDivElement>) => { 
	 // 잠 온다...
}
  • 컴포넌트 내부에서 정의한 props를 사용할 때는 미리 구조 분해 할당해요.
interface AppProps {
  name: number;
  age: number;
}

// BAD 👎
export default function App(props: AppProps) {
	const {name, age} = props
	
	//...
}

// GOOD 👍
export default function App({ name, age }: AppProps) {
	//...
}
  1. 이벤트 핸들러 함수 props
  • 컴포넌트의 prop으로 넘기는 이벤트 핸들러는 on 접두사를 붙여주세요.
  • 이벤트를 직접 처리하는 함수는 handle + 명사 + 동사를 사용해주세요.
  • 같은 파일이면 handle을, 다른 파일에 내려주는거면 on 접두사를 사용해주세요.
// BAD 👎
export default Harry(){
	const onInputChange = () => //...
	
	return <button onClick={onInputChange}></button>
}

// GOOD 👍
export default Harry(){
	const handleInputChange = () => //...
	
	return <button onClick={handleInputChange}></button>
}
// BAD 👎
<Harry
  //...
  handleSomething={onSomething}
/>

// GOOD 👍
<Harry
  //...
  onSomething={handleSomething}
/>
// BAD 👎: handle + 동사 + 동사 + 동사
const handleDODODO = () => //...

// GOOD 👍: handle + 명사 + 동사 
const handleLunchMenuDecide = () => //...
이유 살펴보기

handleClick 함수를 정의하였고 이를 <button>prop 형태로 전달하였습니다. 여기서 handleClick이벤트 핸들러입니다. 이벤트 핸들러 함수는 다음 특징을 가집니다.

  • 주로 컴포넌트 내부에서 정의됩니다.
  • handle로 시작하고 그 뒤에 이벤트명을 붙인 함수명을 가집니다.

*관습적으로 handle로 시작하며 이벤트명을 이어 붙인 이벤트 핸들러 명명법이 일반적입니다. onClick={handleClick}, onMouseEnter={handleMouseEnter}와 같은 경우를 자주 볼 수 있을 것입니다.

…*

위 코드에서는 Toolbar 컴포넌트가 PlayButtonUploadButton을 렌더링합니다.

  • PlayButton은 handlePlayClick을 Button 내 onClick prop으로 전달합니다.
  • UploadButton은 () => alert('Uploading!')을 Button 내 onClick prop으로 전달합니다.

최종적으로, Button 컴포넌트는 onClick prop을 받습니다. 이후 받은 prop을 브라우저 빌트인 <button>onClick={onClick}으로 직접 전달합니다. 이를 통해 React가 전달받은 함수를 클릭 시점에 호출함을 알 수 있습니다.

만약 디자인 시스템을 적용한다면 버튼과 같은 컴포넌트는 동작을 지정하지 않고 스타일만 지정하는 것이 일반적입니다. 그 대신, PlayButtonUploadButton 같은 컴포넌트가 이벤트 핸들러를 전달하도록 합니다.

참고

🪝 훅

  • 원시 타입의 경우 타입 추론을 활용해요.
const [count, setCount] = useState(0);
  • 객체 타입의 경우, 특히 객체의 프로퍼티가 많을 경우 타입을 직접 정의하고 제네릭을 사용해요.
const [harry, setHarry] = useState<Harry>({
  name: 'harry',
  age: '26',
  address: 'busan',
});

🆎 타입

1) type vs interface

공식 문서에서는 두 타입 키워드의 차이를 다음과 같이 설명해요.

*타입 별칭과 인터페이스는 매우 유사하며, 대부분의 경우 둘 중 하나를 자유롭게 선택하여 사용할 수 있습니다.  interface가 가지는 대부분의 기능은 type에서도 동일하게 사용 가능합니다. 이 둘의 가장 핵심적인 차이는, 타입은 새 프로퍼티를 추가하도록 개방될 수 없는 반면, 인터페이스의 경우 항상 확장될 수 있다는 점입니다. 대부분의 경우 개인적 선호에 따라 인터페이스와 타입 중에서 선택할 수 있으며, 필요하다면 TypeScript가 다른 선택을 제안할 것입니다. 잘 모르겠다면, 우선 interface를 사용하고 이후 문제가 발생하였을 때 type을 사용하기 바랍니다.

  • interface

    • 컴포넌트의 props 타입을 정할 때 사용해요.
    • 확장성을 고려해야 하는 타입의 경우(즉, extends 키워드를 사용할 것이라 예상되는 경우) 사용해요.
    • 보통, 객체를 정의할 때 사용해요.
    • interface의 선언 병합(extends)을 통해 속성을 확장시킬 수도 있어요.
  • type

    • 객체 타입을 정의할 때, 매핑된 타입을 활용해야 하는 경우라면 사용해요.
    • 복잡한 타입을 다룰 때 활용하면 좋아요.
      • Union, Intersection, Mapped Type… etc…
    • 타입의 확장 가능 / 불가능 여부이다.
      • 인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능하다. 따라서, 가능한한 type 보다는  interface로 선언해서 사용하는 것을 추천한다.
    • 복잡한 타입을 다룰 때는 type을 사용하는 것이 좋다.
      • 매핑 타입 지원도 된다.

타입스크립트 type과 interface의 차이점 - 버건디의 블로그 ^^

2) Typescript 관련 기타 컨벤션

  • any … 사용하지 말아요 ㅎ
  • 모듈화 한 타입을 import 할 경우에는 import type 으로 가져와요.

🌊 상수

  • 상수 : UPPER_SNAKE_CASE
    • 매직 넘버를 피해요 ^^
    • 문자열에도 의미있는 상수를 적용해요 ^^
    • 클라이언트 url 경로에도 적용하면 좋아요, 사용자를 어디로 보내는지 파악하기 쉬워요^^

상수 네이밍 컨벤션은 아래 예시를 따라줘요.

const CONSTANTS = {
	something: "상수를 입력해주세요!"
}

📂 디렉토리 구조

  • 컴포넌트 이름은 PascalCase로 해요.
  • 컴포넌트를 제외한 다른 파일 이름은 camelCase로 해요.
    • 유틸 함수, 상수 등등…
/Button
	 index.tsx
	 Button.styles.ts
	 Button.stories.tsx
	

/hooks
	 useCardNumber
		 useCardNumbers.ts
		 useCardNumbers.test.ts 

🎨 css

css prop 변수 네이밍 규칙

모든 css prop 변수 네이밍은 s_ prefix를 사용한다.

// example

const s_name = css``;

<div css={s_name}></div>