From 6947274278e4378b68a9e436bf9c19ff677b4447 Mon Sep 17 00:00:00 2001 From: Yeryeong Kang Date: Wed, 3 Jun 2026 15:53:42 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20=EC=B4=88=EA=B8=B0=20=ED=85=9C?= =?UTF-8?q?=ED=94=8C=EB=A6=BF=20=EC=8A=A4=ED=83=80=EC=9D=BC=20App.css=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.css | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) diff --git a/src/App.css b/src/App.css index e69de29..6a3b09b 100644 --- a/src/App.css +++ b/src/App.css @@ -0,0 +1,302 @@ +* { + padding: 0; + margin: 0; + box-sizing: border-box; +} + +ul, +li { + list-style: none; +} + +html, +body { + font-family: sans-serif; + font-size: 16px; +} + +/* Colors *****************************************/ +:root { + --primary-color: #ec4a0a; + --lighten-color: #f6a88a; + --grey-100: #ffffff; + --grey-200: #d0d5dd; + --grey-300: #667085; + --grey-400: #344054; + --grey-500: #000000; +} + +/* Typography *************************************/ +.text-title { + font-size: 20px; + line-height: 24px; + font-weight: 600; +} + +.text-subtitle { + font-size: 18px; + line-height: 28px; + font-weight: 600; +} + +.text-body { + font-size: 16px; + line-height: 24px; + font-weight: 400; +} + +.text-caption { + font-size: 14px; + line-height: 20px; + font-weight: 400; +} + +/* Header ********************************************/ +.gnb { + display: flex; + justify-content: space-between; + align-items: center; + height: 64px; + + padding: 0 16px; + + background-color: var(--primary-color); +} + +.gnb__title { + color: #fcfcfd; +} + +.gnb__button { + height: 40px; + + border: none; + border-radius: 8px; + background: transparent; + + font-size: 24px; + cursor: pointer; +} + +.gnb__button img { + display: block; + width: 40px; + height: 40px; + object-fit: contain; +} + +/* 음식점 목록 *****************************************/ + +/* 카테고리/정렬 필터 */ +.restaurant-filter-container { + display: flex; + justify-content: space-between; + + padding: 0 16px; + margin-top: 24px; +} + +.restaurant-filter-container select { + height: 44px; + min-width: 125px; + + border: 1px solid #d0d5dd; + border-radius: 8px; + background: transparent; + + font-size: 16px; +} + +.restaurant-filter { + padding: 8px; +} + +/* 음식점 목록 */ +.restaurant-list-container { + display: flex; + flex-direction: column; + + padding: 0 16px; + margin: 16px 0; +} + +.restaurant { + display: flex; + align-items: flex-start; + + padding: 16px 8px; + + border-bottom: 1px solid #e9eaed; +} + +.restaurant__category { + display: flex; + justify-content: center; + align-items: center; + width: 64px; + height: 64px; + min-width: 64px; + min-height: 64px; + + margin-right: 16px; + + border-radius: 50%; + background: var(--lighten-color); +} + +.category-icon { + width: 36px; + height: 36px; +} + +.restaurant__info { + display: flex; + flex-direction: column; + justify-content: flex-start; +} + +.restaurant__name { + margin: 0; +} + +.restaurant__distance { + color: var(--primary-color); +} + +.restaurant__description { + display: -webkit-box; + + padding-top: 8px; + + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +/* 음식점 정보/추가 모달 *****************************************/ +.modal { + display: none; +} + +.modal--open { + display: block; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + + background: rgba(0, 0, 0, 0.35); +} + +.modal-container { + position: fixed; + bottom: 0; + width: 100%; + + padding: 32px 16px; + + border-radius: 8px 8px 0px 0px; + background: var(--grey-100); +} + +.modal-title { + margin-bottom: 36px; +} + +.form-item { + display: flex; + flex-direction: column; + + margin-bottom: 36px; +} + +.form-item label { + color: var(--grey-400); + font-size: 14px; +} + +.form-item--required label::after { + padding-left: 4px; + + color: var(--primary-color); + content: "*"; +} + +.form-item .help-text { + color: var(--grey-300); +} + +.form-item input, +.form-item textarea, +.form-item select { + padding: 8px; + margin: 6px 0; + + border: 1px solid var(--grey-200); + border-radius: 8px; + + font-size: 16px; +} + +.form-item textarea { + resize: none; +} + +.form-item select { + height: 44px; + + padding: 8px; + + border: 1px solid var(--grey-200); + border-radius: 8px; + + color: var(--grey-300); +} + +input[name="name"], +input[name="link"] { + height: 44px; +} + +.button-container { + display: flex; +} + +.button { + width: 100%; + height: 44px; + + margin-right: 16px; + + border: none; + border-radius: 8px; + + font-weight: 600; + cursor: pointer; +} + +.button:last-child { + margin-right: 0; +} + +.button--secondary { + border: 1px solid var(--grey-300); + background: transparent; + + color: var(--grey-300); +} + +.button--primary { + background: var(--primary-color); + + color: var(--grey-100); +} + +.restaurant-info { + margin-bottom: 24px; +} From 731955f546a710fa3a291077ca61da73d907d20c Mon Sep 17 00:00:00 2001 From: Yeryeong Kang Date: Wed, 3 Jun 2026 15:56:36 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20=ED=85=9C=ED=94=8C=EB=A6=BF=20htm?= =?UTF-8?q?l=20->=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20jsx=20=EB=AC=B8=EB=B2=95=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AddRestaurantModal.jsx | 49 +++++++++++++++ src/App.jsx | 19 +++++- src/CategoryFilter.jsx | 20 ++++++ src/Header.jsx | 10 +++ src/RestaurantDetailModal.jsx | 19 ++++++ src/RestaurantList.jsx | 115 ++++++++++++++++++++++++++++++++++ 6 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 src/AddRestaurantModal.jsx create mode 100644 src/CategoryFilter.jsx create mode 100644 src/Header.jsx create mode 100644 src/RestaurantDetailModal.jsx create mode 100644 src/RestaurantList.jsx diff --git a/src/AddRestaurantModal.jsx b/src/AddRestaurantModal.jsx new file mode 100644 index 0000000..e2bd0c2 --- /dev/null +++ b/src/AddRestaurantModal.jsx @@ -0,0 +1,49 @@ +export default function AddRestaurantModal() { + return ( +
+
+
+

새로운 음식점

+
+ {/* 카테고리 */} +
+ + +
+ {/* 음식점 이름 */} +
+ + +
+ {/* 설명 */} +
+ + + + 메뉴 등 추가 정보를 입력해 주세요. + +
+ {/* 추가 버튼 */} +
+ +
+
+
+
+ ); +} diff --git a/src/App.jsx b/src/App.jsx index 0f5bcc1..57d97d8 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,24 @@ import "./App.css"; +import Header from "./Header"; +import CategoryFilter from "./CategoryFilter"; +import RestaurantList from "./RestaurantList"; +import RestaurantDetailModal from "./RestaurantDetailModal"; +import AddRestaurantModal from "./AddRestaurantModal"; function App() { - return

Self-Paced React

; + return ( + <> +
+
+ + +
+ + + ); } export default App; diff --git a/src/CategoryFilter.jsx b/src/CategoryFilter.jsx new file mode 100644 index 0000000..bd9cf85 --- /dev/null +++ b/src/CategoryFilter.jsx @@ -0,0 +1,20 @@ +export default function CategoryFilter() { + return ( +
+ +
+ ); +} diff --git a/src/Header.jsx b/src/Header.jsx new file mode 100644 index 0000000..bcea300 --- /dev/null +++ b/src/Header.jsx @@ -0,0 +1,10 @@ +export default function Header() { + return ( +
+

점심 뭐 먹지

+ +
+ ); +} diff --git a/src/RestaurantDetailModal.jsx b/src/RestaurantDetailModal.jsx new file mode 100644 index 0000000..c535c5c --- /dev/null +++ b/src/RestaurantDetailModal.jsx @@ -0,0 +1,19 @@ +export default function RestaurantDetailModal() { + return ( +
+
+
+

음식점 이름

+
+

+ 음식점 소개 문구 +

+
+ {/* 닫기 버튼 */} +
+ +
+
+
+ ); +} diff --git a/src/RestaurantList.jsx b/src/RestaurantList.jsx new file mode 100644 index 0000000..045efc0 --- /dev/null +++ b/src/RestaurantList.jsx @@ -0,0 +1,115 @@ +export default function RestaurantList() { + return ( +
+
    +
  • +
    + 한식 +
    +
    +

    피양콩할마니

    +

    + 평양 출신의 할머니가 수십 년간 운영해온 비지 전문점 피양콩 할마니. + 두부를 빼지 않은 되비지를 맛볼 수 있는 곳으로, ‘피양’은 평안도 + 사투리로 ‘평양’을 의미한다. 딸과 함께 운영하는 이곳에선 맷돌로 + 직접 간 콩만을 사용하며, 일체의 조미료를 넣지 않은 건강식을 + 선보인다. 콩비지와 피양 만두가 이곳의 대표 메뉴지만, 할머니가 옛날 + 방식을 고수하며 만들어내는 비지전골 또한 이 집의 역사를 느낄 수 + 있는 특별한 메뉴다. 반찬은 손님들이 먹고 싶은 만큼 덜어 먹을 수 + 있게 준비돼 있다. +

    +
    +
  • + +
  • +
    + 중식 +
    +
    +

    친친

    +

    + Since 2004 편리한 교통과 주차, 그리고 관록만큼 깊은 맛과 정성으로 + 정통 중식의 세계를 펼쳐갑니다 +

    +
    +
  • + +
  • +
    + 일식 +
    +
    +

    잇쇼우

    +

    + 잇쇼우는 정통 자가제면 사누끼 우동이 대표메뉴입니다. 기술은 정성을 + 이길 수 없다는 신념으로 모든 음식에 최선을 다하는 잇쇼우는 고객 + 한분 한분께 최선을 다하겠습니다 +

    +
    +
  • + +
  • +
    + 양식 +
    +
    +

    이태리키친

    +

    + 늘 변화를 추구하는 이태리키친입니다. +

    +
    +
  • + +
  • +
    + 아시안 +
    +
    +

    호아빈 삼성점

    +

    + 푸짐한 양에 국물이 일품인 쌀국수 +

    +
    +
  • + +
  • +
    + 기타 +
    +
    +

    + 도스타코스 선릉점 +

    +

    + 멕시칸 캐주얼 그릴 +

    +
    +
  • +
+
+ ); +} From 8026911ec0babe44829b2f6c739649363b27c620 Mon Sep 17 00:00:00 2001 From: Yeryeong Kang Date: Wed, 3 Jun 2026 15:57:31 +0900 Subject: [PATCH 03/10] =?UTF-8?q?docs:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20README=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 02-rendering-lists/README.md | 74 ------------------- 03-modal/README.md | 24 ------- 04-form/README.md | 38 ---------- 05-effects/README.md | 49 ------------- 06-references/README.md | 16 ----- README.md | 135 ++++++++++++++++++++++------------- 6 files changed, 87 insertions(+), 249 deletions(-) delete mode 100644 02-rendering-lists/README.md delete mode 100644 03-modal/README.md delete mode 100644 04-form/README.md delete mode 100644 05-effects/README.md delete mode 100644 06-references/README.md diff --git a/02-rendering-lists/README.md b/02-rendering-lists/README.md deleted file mode 100644 index 55bbadb..0000000 --- a/02-rendering-lists/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# 02. 목록 UI 구현하기: Props와 State - -## 🎯 요구 사항 -- `RestaurantList` 가 restaurants 배열을 받아서 그릴 수 있도록 변경해 보세요. - - restaurants 배열을 `RestaurantList` 의 props로 내려받도록 변경해 보세요. -- 카테고리 필터에 따라 필터된 음식점 목록을 보여줄 수 있도록 변경해 보세요. - -### 구현 결과 예시 -```javascript -// App.jsx - - -``` -```javascript -const restaurants = [ - { - id: "a01", - name: "피양콩할마니", - description: - "평양 출신의 할머니가 수십 년간 운영해온 비지 전문점 피양콩 할마니. 두부를 빼지 않은 되비지를 맛볼 수 있는 곳으로, ‘피양’은 평안도 사투리로 ‘평양’을 의미한다. 딸과 함께 운영하는 이곳에선 맷돌로 직접 간 콩만을 사용하며, 일체의 조미료를 넣지 않은 건강식을 선보인다. 콩비지와 피양 만두가 이곳의 대표 메뉴지만, 할머니가 옛날 방식을 고수하며 만들어내는 비지전골 또한 이 집의 역사를 느낄 수 있는 특별한 메뉴다. 반찬은 손님들이 먹고 싶은 만큼 덜어 먹을 수 있게 준비돼 있다.", - category: "한식", - }, - { - id: "a02", - name: "친친", - description: "Since 2004 편리한 교통과 주차, 그리고 관록만큼 깊은 맛과 정성으로 정통 중식의 세계를 펼쳐갑니다", - category: "중식", - }, - { - id: "a03", - name: "잇쇼우", - description: - "잇쇼우는 정통 자가제면 사누끼 우동이 대표메뉴입니다. 기술은 정성을 이길 수 없다는 신념으로 모든 음식에 최선을 다하는 잇쇼우는 고객 한분 한분께 최선을 다하겠습니다", - category: "일식", - }, - { - id: "a04", - name: "이태리키친", - description: "늘 변화를 추구하는 이태리키친입니다.", - category: "양식", - }, - { - id: "a05", - name: "호아빈 삼성점", - description: "푸짐한 양에 국물이 일품인 쌀국수", - category: "아시안", - }, - { - id: "a06", - name: "도스타코스 선릉점", - description: "멕시칸 캐주얼 그릴", - category: "기타", - }, -]; -``` - - -## ✅ 키워드 -- Props -- State - - useState -- Keys - -> [Rendering Lists](https://react.dev/learn/rendering-lists) 문서에 ['Why does React need keys?'](https://react.dev/learn/rendering-lists#why-does-react-need-keys)는 지금 꼭 이해하지 않아도 괜찮습니다. 그냥 React에서 목록을 동적으로 그릴 때에는 이런 것들을 사용해야 하는구나~ 정도로만 알고 일단 넘어가세요. 우선 사용하는 법에 익숙해지는 것이 먼저입니다 :) - -## 🧙‍♀️ 진행 가이드 -- 진행 시간: 1시간 내에 완료하는 것을 목표로 합니다. - -## 🔗 참고 문서 -- [Thinking in React](https://react.dev/learn/thinking-in-react)의 Step3-4 -- [Passing Props to a Component](https://react.dev/learn/passing-props-to-a-component) -- [Rendering Lists](https://react.dev/learn/rendering-lists) -- [State: A Component's Memory](https://react.dev/learn/state-a-components-memory) - - [API Reference: useState](https://react.dev/reference/react/useState) diff --git a/03-modal/README.md b/03-modal/README.md deleted file mode 100644 index 6ad102e..0000000 --- a/03-modal/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# 03. 모달 UI 구현하기: side-effect(feat. event handler) - -## 🎯 요구 사항 -- `RestaurantList` 의 아이템을 클릭하면, 클릭한 아이템의 정보를 보여주는 모달이 뜨도록 변경해 주세요. '확인' 버튼을 클릭하거나 모달 뒤의 backdrop을 클릭하면 모달이 닫혀야 합니다. - - (작은 단계로 구현해보기 1) 아이템을 클릭하면 정해진 텍스트를 그대로 보여주는 모달을 열고 닫습니다. - - (작은 단계로 구현해보기 2) 클릭한 아이템의 정보를 모달에 내려줄 수 있도록 개선합니다. - -### 구현 결과 예시 -```javascript -// App.jsx -{isModalOpen && } -``` - -## ✅ 키워드 -- event handler (feat. side effect) -- conditional rendering -- lifting state up - -## 🧙‍♀️ 진행 가이드 -- 진행 시간: 1시간 내에 완료하는 것을 목표로 합니다. - -## 🔗 참고 문서 -- [Thinking in React](https://react.dev/learn/thinking-in-react)의 Step5 -- [Responding to Events](https://react.dev/learn/responding-to-events) diff --git a/04-form/README.md b/04-form/README.md deleted file mode 100644 index 45a5bd0..0000000 --- a/04-form/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# 04. 폼 UI 구현하기: controlled vs uncontrolled - -## 🎯 요구 사항 -- `Header`의 레스토랑 추가 버튼을 클릭하면 레스토랑 추가 폼이 모달로 뜨도록 구현해 주세요 - - 이전 단계에서 만들어두었던 `AddRestaurantModal`을 그대로 사용합니다. -- 카테고리를 선택하고, ``, ` - + 메뉴 등 추가 정보를 입력해 주세요. {/* 추가 버튼 */} -
-
diff --git a/src/CategoryFilter.jsx b/src/CategoryFilter.jsx index bd9cf85..243d3c5 100644 --- a/src/CategoryFilter.jsx +++ b/src/CategoryFilter.jsx @@ -1,10 +1,12 @@ +import styles from "./CategoryFilter.module.css"; + export default function CategoryFilter() { return ( -
+
을 연결하는 속성으로, htmlFor에 지정한 값과 id가 일치하는 입력 요소에 포커스를 연결한다. 레이블 클릭 시 연결된 입력 요소가 활성화된다. + +| HTML | JSX | 이유 | +| ------- | ----------- | ----------------------------------------- | +| `for` | `htmlFor` | `for`는 JavaScript의 반복문 예약어 | +| `class` | `className` | `class`는 JavaScript의 클래스 선언 예약어 | + +```html + + + +``` + +```jsx +// JSX + + +``` + --- -## 🤔 고민했던 문제와 해결 과정에서 배운 점 +### 4. CSS Module + +CSS Module은 클래스명을 파일 단위로 자동 고유화하여 스타일이 다른 컴포넌트에 영향을 미치지 않도록 격리하는 방식이다. + +일반 CSS는 클래스명이 전역으로 적용되므로 프로젝트 규모가 커질수록 클래스명 충돌이 발생할 수 있다. CSS Module을 사용하면 동일한 클래스명을 각 파일에서 독립적으로 사용할 수 있다. + +**사용법** + +파일명을 `*.module.css`로 작성하고, JS 파일에서 객체로 import하여 사용한다. + +```css +/* Button.module.css */ +.button { + background-color: blue; + color: white; +} +``` + +```jsx +// Button.jsx +import styles from "./Button.module.css"; + +function Button() { + return ; +} +``` + +빌드 후 실제 클래스명은 `Button_button__xK2f`처럼 고유한 이름으로 변환되어 다른 컴포넌트의 `.button`과 충돌하지 않는다. --- +## 🤔 고민했던 문제와 해결 과정에서 배운 점 + +### CSS Module 적용 + +**1. 전역 스타일과 CSS Module의 분리 기준** + +CSS Module은 클래스명에 해시값을 붙여 스코프를 격리하기 때문에, 전역으로 적용해야 하는 여백, 폰트, 색상 변수 같은 스타일에는 적합하지 않다. 모든 태그에 `styles.body`처럼 객체로 접근해야 하므로 오히려 사용이 번거로워진다. + +이를 해결하기 위해 컴포넌트 단위로 격리가 필요한 스타일은 `*.module.css`로 모듈화하고, 전역 스타일은 `App.css`에 정의하여 `App.jsx` 상단에서 일반 import로 불러오는 방식으로 분리했다. + +**2. 하이픈(-)이 포함된 클래스명 접근 방법** + +CSS Module을 import하면 점 표기법(`styles.className`)으로 클래스에 접근한다. 언더바(`_`)는 정상 동작하지만, 하이픈(`-`)이 포함된 클래스명은 JavaScript가 빼기 연산자로 인식하여 에러가 발생한다. + +JavaScript 객체에서 특수문자가 포함된 키에 접근할 때 사용하는 대괄호 표기법으로 해결할 수 있다. + +```jsx +className={styles['class-name']} +``` + +**3. 전역 클래스와 모듈 클래스를 함께 사용하는 방법** + +하나의 태그에 전역 스타일 클래스와 CSS Module 클래스를 동시에 적용해야 하는 경우, 템플릿 리터럴을 활용한다. + +```jsx +className={`${styles.gnb__title} text-title`} +``` + +- `{ }`: JSX에서 JavaScript 표현식을 사용할 때 사용한다. +- 백틱(`` ` ``): 변수와 문자열을 혼합할 수 있는 템플릿 리터럴 문자열을 만든다. +- `${ }`: 템플릿 리터럴 안에서 JavaScript 변수나 표현식의 실제 값으로 치환한다. + +**4. `htmlFor` 속성 오류** + +HTML 템플릿에 아래와 같이 작성된 코드가 있었다. + +```html + +``` + +`htmlFor`에 연결 대상 `id`인 `"category"`와 스타일 클래스명인 `"text-caption"`이 함께 들어가 있었다. `htmlFor`는 연결할 입력 요소의 `id` 하나만 받는 속성이므로, 스타일 클래스는 `className`으로 분리해야 한다. 이 상태로는 폰트 스타일도 적용되지 않고, 라벨 클릭 시 입력 요소로 포커스도 이동하지 않는다. + +```jsx +// 수정 전 +; + +// 수정 후 +; +``` + ## 🛠 리팩토링 --- From d9f8a3fb71af3ae1072477ff95bc0e4dd3d5e9ae Mon Sep 17 00:00:00 2001 From: Kang Yeryeong Date: Wed, 3 Jun 2026 17:18:27 +0900 Subject: [PATCH 07/10] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dd356c9..430a3a0 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ 이번 미션을 통해 다음과 같은 학습 경험들을 쌓는 것을 목표로 한다. -1. React의 원칙과 특성 이해 +**1. React의 원칙과 특성 이해** React 공식 문서의 Quick Start를 읽으며 기존에 알고 있던 React 지식을 비교하고 재정리한다. -2. HTML과 JSX의 차이점 이해 +**2. HTML과 JSX의 차이점 이해** 주어진 HTML 템플릿을 `App.jsx`로 변환하는 과정을 직접 실습하며 두 문법의 차이점을 이해한다. -3. 컴포넌트 분리 기준 정립 +**3. 컴포넌트 분리 기준 정립** UI를 컴포넌트 단위로 분리하는 기준을 스스로 고민하고 세워본다. -4. CSS Module 사용 및 특성 이해 +**4. CSS Module 사용 및 특성 이해** `module.css`를 직접 사용해보고, 일반 CSS와의 차이점 및 특성을 이해한다. --- From 14b58d5173b1459a7bd5e796e21ac03a3ac18b34 Mon Sep 17 00:00:00 2001 From: Kang Yeryeong Date: Wed, 3 Jun 2026 17:24:04 +0900 Subject: [PATCH 08/10] Update README.md --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 430a3a0..c34a8ce 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,20 @@ 이번 미션을 통해 다음과 같은 학습 경험들을 쌓는 것을 목표로 한다. **1. React의 원칙과 특성 이해** - React 공식 문서의 Quick Start를 읽으며 기존에 알고 있던 React 지식을 비교하고 재정리한다. + +React 공식 문서의 Quick Start를 읽으며 기존에 알고 있던 React 지식을 비교하고 재정리한다. **2. HTML과 JSX의 차이점 이해** - 주어진 HTML 템플릿을 `App.jsx`로 변환하는 과정을 직접 실습하며 두 문법의 차이점을 이해한다. + +주어진 HTML 템플릿을 `App.jsx`로 변환하는 과정을 직접 실습하며 두 문법의 차이점을 이해한다. **3. 컴포넌트 분리 기준 정립** - UI를 컴포넌트 단위로 분리하는 기준을 스스로 고민하고 세워본다. + +UI를 컴포넌트 단위로 분리하는 기준을 스스로 고민하고 세워본다. **4. CSS Module 사용 및 특성 이해** - `module.css`를 직접 사용해보고, 일반 CSS와의 차이점 및 특성을 이해한다. + +`module.css`를 직접 사용해보고, 일반 CSS와의 차이점 및 특성을 이해한다. --- @@ -187,6 +191,8 @@ HTML 템플릿에 아래와 같이 작성된 코드가 있었다. ## 🛠 리팩토링 +해당 미션은 Step2와 이어서 진행했기 때문에 스터디 이후 cactus-step2 브랜치에서 한 번에 리팩토링을 진행한다. + --- ## 과거 코드와 비교 From 4a30e814e0815245782e8348a5945fec1c237f83 Mon Sep 17 00:00:00 2001 From: Kang Yeryeong Date: Wed, 3 Jun 2026 17:24:58 +0900 Subject: [PATCH 09/10] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index c34a8ce..40691bc 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,6 @@ HTML의 일부 속성은 JavaScript의 예약어와 이름이 겹치기 때문 ``` ---- - ### 4. CSS Module CSS Module은 클래스명을 파일 단위로 자동 고유화하여 스타일이 다른 컴포넌트에 영향을 미치지 않도록 격리하는 방식이다. From e7094849686a00ef68568974be4da84d7c59964a Mon Sep 17 00:00:00 2001 From: Kang Yeryeong Date: Fri, 12 Jun 2026 11:20:33 +0900 Subject: [PATCH 10/10] Fix markdown formatting for htmlFor in README Updated markdown formatting for htmlFor explanation. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40691bc..d02b045 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ React(core)는 **무엇을 그릴지**만 계산하고, Renderer가 **어디에 HTML의 일부 속성은 JavaScript의 예약어와 이름이 겹치기 때문에 JSX에서는 다른 이름을 사용해야 한다. -- htmlFor는