폴더 구조
폴더가 너무 많아도 그리고 너무 중첩되어도 좋지 않다
타입이 중복되어 사용된다면
types
폴더 하나에서 관리할 수 있도록 하자.d.ts
파일보다는 .ts
파일에서 export 를 이용하자├── api ├── assets ├── components │ └── Button │ ├── Button.styles.ts │ ├── Button.tsx │ └── index.ts ├── constants ├── hooks ├── recoil ├── pages ├── styles ├── interfaces ├── types └── utils
스타일드 컴포넌트
백틱 형식을 오브젝트 형태로 통일하자
현재
common.ts
에 있는 컴포넌트를 components
폴더로 옮기자 ⇒ 이것도 또한 컴포넌트이기 때문에CSS 프로퍼티 순서
.selector { /* Positioning */ position: absolute; z-index: 10; top: 0; right: 0; /* Display & Box Model */ display: inline-block; overflow: hidden; box-sizing: border-box; width: 100px; height: 100px; padding: 10px; border: 10px solid #333; margin: 10px; /* Color */ background: #000; color: #fff /* Text */ font-family: sans-serif; font-size: 16px; line-height: 1.4; text-align: right; /* Other */ cursor: pointer; }
import 문 정렬
"import/order": [ "error", { "groups": ["builtin", "external", "internal", ["parent", "sibling"], "index"], "alphabetize": { "order": "asc", "caseInsensitive": true }, "newlines-between": "always" } ]
네이밍
컴포넌트명은 파스칼 케이스 ex) Header, Button
변수명, 함수명은 카멜 케이스 ex) isLogin
타입
파스칼 케이스로 Prefix 없이 정의한다.
Props는 해당 타입이 사용되는 파일 내부에 정의한다.
interface Props { name: String, password: String } const Login = ({ name, password }: Props) => { return (); }
핸들러 함수
Prefix로
handle
을 사용한다.const handleChange = () => {}
핸들러 함수의 타입은
React.ChangeEventHandler<HTMLInputElement>
와 같은 형태로 통일한다.onChange: React.ChangeEventHandler<HTMLInputElement>
Prettier
코드 포맷팅을 위한 Prettier 설정은 아래와 같다.
{ "printWidth": 120, "tabWidth": 2, "singleQuote": true, "semi": true, "bracketSpacing": true, "bracketSameLine": false, "jsxSingleQuote": true, "trailingComma": "all", "useTabs": false, "singleAttributePerLine": true, "endOfLine": "auto" }
Lint
코드 린팅을 위한 ESLint 설정은 아래와 같다.
만약 새로운 룰이 필요하거나 기존 룰 중에서 사용하지 않아야 할 룰이 있는 경우
1. 추가하거나 삭제해야 하는 이유를 노션에 문서로 정리한다.
2. 정리한 내용을 바탕으로 팀원들과 상의 후 결정한다.
{ "root": true, "parser": "@typescript-eslint/parser", "parserOptions": { "tsConfigRootDir": "./", "project": "./tsconfig.json" }, "plugins": ["@typescript-eslint"], "extends": [ "next/core-web-vitals", "airbnb", "airbnb-typescript", "plugin:react/jsx-runtime", "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", "prettier" ] }
함수 정의
function 키워드 대신 화살표 함수를 사용한 함수 표현식으로 함수를 정의한다.
const handleSubmit = () => {}; const ComponentName = () => { return <div>hello</div>; }; export default ComponentName;
Container? Wrapper?
단일 요소를 감싸야 한다면
Wrapper
<Wrapper> <span>hi</span> </Wrapper>
2개 이상의 요소를 감싸야 한다면
Container
<Container> <img src='/img/good.png' /> <span>hi</span> </Container>
API 로직
// API 요청 함수 분리 const fetch = async (id: number) => { try { const { data: { data }, } = await axiosAuthInstance.get<Response<MatchRecord>>(`/api/matches/records`, { params: { userId: id }, }); return data } catch (error) { // 에러 처리 } } // 컴포넌트 내부 API 요청 React.useEffect(() => { setIsMatchLoading(true); (async () => { const matchRecord = await fetch(); setmatchRecord(() => matchRecord)); setIsMatchLoading(false); })(); }, [router.isReady])