포스트

2024.06.23 프로그래머스 - React Task Management 1

React 로 만드는 Task Management App 1

  • Trello 같은 웹 사이트를 제작!

프로젝트 생성

  • CRA 와 Vite중 Vite를 이용하여 프로젝트 생성
1
npm init vite
  • framework : React
  • variant : Typescript
  • 위의 기술로 프로젝트 생성
  • 생성 후 npm install로 의존성 설정

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "name": "react-task-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.66",
    "@types/react-dom": "^18.2.22",
    "@typescript-eslint/eslint-plugin": "^7.2.0",
    "@typescript-eslint/parser": "^7.2.0",
    "@vitejs/plugin-react": "^4.2.1",
    "eslint": "^8.57.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.6",
    "typescript": "^5.2.2",
    "vite": "^5.2.0"
  }
}

프로젝트 구조 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

react-task-app
├─ src
│  ├─ App.css
│  ├─ App.tsx
│  ├─ components
│  │  ├─ ActionButton
│  │  │  ├─ ActionButton.css.ts
│  │  │  ├─ ActionButton.tsx
│  │  │  └─ DropdownForm
│  │  │     ├─ DropdownForm.css.ts
│  │  │     └─ DropdownForm.tsx
│  │  ├─ BoardList
│  │  │  ├─ BoardList.css.ts
│  │  │  ├─ BoardList.tsx
│  │  │  └─ SideForm
│  │  │     ├─ SideForm.css.ts
│  │  │     └─ SideForm.tsx
│  │  ├─ EditModal
│  │  │  ├─ EditModal.css.ts
│  │  │  └─ EditModal.tsx
│  │  ├─ List
│  │  │  ├─ List.css.ts
│  │  │  └─ List.tsx
│  │  ├─ ListsContainer
│  │  │  ├─ ListsContainer.css.ts
│  │  │  └─ ListsContainer.tsx
│  │  ├─ LoggerModal
│  │  │  ├─ LoggerModal.css.ts
│  │  │  ├─ LoggerModal.tsx
│  │  │  └─ LogItem
│  │  │     ├─ LogItem.css.ts
│  │  │     └─ LogItem.tsx
│  │  └─ Task
│  │     ├─ Task.css.ts
│  │     └─ Task.tsx
│  ├─ hooks
│  │  └─ redux.ts
│  ├─ index.css
│  ├─ main.tsx
│  ├─ store
│  │  ├─ index.ts
│  │  ├─ reducer
│  │  │  └─ reducer.ts
│  │  └─ slices
│  │     ├─ boardsSlice.ts
│  │     ├─ loggerSlice.ts
│  │     └─ modalSlice.ts
│  ├─ types
│  │  └─ index.ts
│  └─ vite-env.d.ts
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.ts
  • src 내의 폴더 구조를 주목
  • components
    • 재사용 가능한 컴포넌트를 저장하는 위치
  • hooks
    • custom hook을 만들어 저장하는 위치
  • types
    • 재사용하는 type들을 저장하는 위치
  • store
    • Redux 의 소스를 저장하는 위치

이렇게 컴포넌트들을 미리 생성한다는 생각도 못했고, 이렇게 미리 쪼개놓은 상태로 시작하면 효율적일 것도 몰랐다. components 안에서 역할별 폴더를 또 따로 만들어서 세부적으로 또 나누어 놓는 방법 너무 유용하다.

프로젝트 의존성 설치

전역 상태 관리를 위한 라이브러리

  • Redux + Redux Toolkit

동적 className을 위한 라이브러리

  • clsx

CSS 를 위한 라이브러리

  • vanila-extract-css
    • utils
    • vite-plugin

기타 라이브러리

  • react-icons
  • uuid
  • react-beautiful-dnd

설치후 package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{

  "dependencies": {
    "@reduxjs/toolkit": "^2.2.5",
    "@vanilla-extract/css": "^1.15.3",
    "@vanilla-extract/css-utils": "^0.1.4",
    "@vanilla-extract/vite-plugin": "^4.0.11",
    "react": "^18.2.0",
    "react-beautiful-dnd": "^13.1.1",
    "react-dom": "^18.2.0",
    "react-icons": "^5.2.1",
    "redux": "^5.0.1",
    "uuid": "^10.0.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.66",
    "@types/react-dom": "^18.2.22",
    "@typescript-eslint/eslint-plugin": "^7.2.0",
    "@typescript-eslint/parser": "^7.2.0",
    "@vitejs/plugin-react": "^4.2.1",
    "eslint": "^8.57.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.6",
    "typescript": "^5.2.2",
    "vite": "^5.2.0"
  }
}

Redux 준비

  • Redux는 상태를 관리 하는 라이브러리
  • 기본 state, props로도 상태 관리는 가능하나, 앱이 커지면 관리가 힘들어지고 소스가 지저분해진다.
  • 이를 효율적으로 관리하기 위해 Redux 와 같은 전역적인 상태 관리가 가능한 라이브러리를 사용

Redux의 흐름

  1. Action = 객체, Dispatch = 함수 ⇒ Reducer = 함수
  2. Reducer의 type 에 따라 Redux Store에 있는 State에 업데이트를 한다.
  3. React Component 가 리 렌더링 된다.

Redux store 생성

  1. 각 상태를 사용할 Slice 생성 (createSlice)
  2. 생성 한 slice의 reducer를 하나의 reducer로 생성 후 export (slice.reducer)
  3. configureStore를 통해 하나로 모은 reducer를 store의 reducer 객체로 할당 후 export default
  4. main.tsx에서 react-redux 라이브러리의 Provider를 통해 전역 상태 설정 및 store 변수 할당

세부 redux 설정은 github 참고

  • https://github.com/ykdman/Programmers-DevCourse/tree/main/react-task-app

전역 스타일 생성하기

  • vanila-extract/css 를 이용하여 전역적인 :root 에 대한 스타일링과, 각 요소별 스타일링 설정
  • App.css.ts

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    
      // App 전역 스타일링
        
      import { createGlobalTheme, style } from "@vanilla-extract/css";
        
      export const vars = createGlobalTheme(":root", {
        color: {
          main: "#ffa726",
          mainDarker: "#f57c00",
          mainFaded: "#ffb74d",
          mainFadedBright: "#ffb75a6",
          list: "rgb(235,236,240)",
          task: "rgb(255,255,255)",
          taskHover: "rgb(245,245,245)",
          brightText: "rgv(255,255,255)",
          darkText: "rgb(24,42,77)",
          secondaryDarkText: "rgb(94,108,132)",
          secondaryDarkTextHover: "rgb(218,219,226)",
          selectedTab: "rgb(137,176,174)",
          updateButton: "rgb(237,180,88)",
          deleteButton: "rgb(237,51,88)",
        },
        fontSizing: {
          T1: "32px",
          T2: "24px",
          T3: "18px",
          T4: "14px",
          P1: "12px",
        },
        spacing: {
          small: "5px",
          medium: "10px",
          big1: "20px",
          big2: "15px",
          listSpacing: "30px",
        },
        font: {
          body: "arial",
        },
        shadow: {
          basic: "4px 4px 8px 0px rgba(34,60,80, 0.2)",
        },
        minWidth: {
          list: "250px",
        },
      });
        
      export const appContainer = style({
        display: "flex",
        flexDirection: "column",
        minHeight: "100vh",
        height: "max-content",
        width: "100vw",
      });
        
      export const board = style({
        display: "flex",
        flexDirection: "row",
        height: "100%",
      });
        
      export const buttons = style({
        marginTop: "auto",
        padding: vars.spacing.big2,
      });
        
    
  • App.tsx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
      import { appContainer, board, buttons } from "./App.css.ts";
      import reactLogo from "./assets/react.svg";
        
      function App() {
        return (
          <div className={appContainer}>
            <div className={board}></div>
        
            <div>
              <button className={buttons}>이 게시판 삭제하기</button>
              <button></button>
            </div>
          </div>
        );
      }
        
      export default App;
        
    

오늘 느낀점

Redux를 이전에 한 번 공부해보긴 했는데, 생각보다 사용법이 훨씬 복잡하고, 신경써줘야 할 부분이 많았다.

일단 Redux 공식 문서를 통해서 RTK (Redux-Toolkit) 과 Redux의 원리 및 사용법을 이해하고 또한 이것이 다른 라이브러리로는 어떻게 대체될 수 있는지에 대해 고민하는 시간이 필요할 것 같다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.