diff --git a/01-styled-components/README.md b/01-styled-components/README.md new file mode 100644 index 0000000..3776be6 --- /dev/null +++ b/01-styled-components/README.md @@ -0,0 +1,91 @@ +# 01. styled-components를 적용해서 리팩토링하기 + +## 🎯 요구사항 + +- 초록스터디-`self-paced-react`의 step5 코드를 가져와 스타일링하는 미션입니다. +- styled-components 라이브러리를 이용해서 컴포넌트들에게 css를 입히고 스타일링 해보세요. +- styled-components를 왜 사용하는지, 별도의 css파일로 분리한 방법과 어떤 trade-off가 있는지 PR에 적어주세요. + - (선택) 브라우저가 웹 페이지를 렌더링하는 구조와 과정에 대해서도 공부해보세요. + - **🔑keywords** : DOM Tree, CSSOM Tree, Render Tree +- 프로젝트내 별도의 css파일은 존재하지 않아야합니다.❌ + - App.css는 허용되며 아래의 코드와 동일해야합니다. + +```css +* { + 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; +} +``` + +### 😗구현 예시 + +- 컴포넌트의 이름이나 구조는 마음대로 변경해도 좋습니다. + +```javascript +import React from "react"; +import styled from "styled-components"; + +// Button 컴포넌트를 styled-components로 정의 +const Button = styled.button` + background-color: #ec4a0a; + color: white; + border: none; + border-radius: 8px; + padding: 10px 20px; + font-size: 16px; + cursor: pointer; + + &:hover { + background-color: #f6a88a; + } +`; + +const App = () => { + return ( +
+

Hello, styled-components!

+ +
+ ); +}; + +export default App; +``` + +## ✅ 키워드 + +- **styled-component** + - Css in JS + - Scoped Styling + +## 🧙‍♀️ 진행 가이드 + +- 진행시간 : 1시간 내에 완료하는 것을 목표로 합니다. +- vscode 사용시 extension에서 `vscode-styled-components`를 설치해주세요. + +## 🔗 참고 문서 + +- [styled-components 공식문서](https://styled-components.com/docs) diff --git a/05-effects/README.md b/05-effects/README.md deleted file mode 100644 index ebebf77..0000000 --- a/05-effects/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# 05. API 연동하기: side-effect(feat. effects) - -## 🎯 요구 사항 - -- API로 레스토랑 목록을 불러와 ``에 내려줍니다. - - 로딩 상태, 에러 상태 등은 고려하지 않습니다. -- 레스토랑 추가 모달에서 추가하기 버튼을 클릭하면 POST 요청을 보냅니다. 모달이 닫히고, 레스토랑 목록을 다시 불러옵니다. - -## ✅ 키워드 - -- effect (feat. side effect) - - useEffect - -## 🧙‍♀️ 진행 가이드 - -- 진행 시간: 2시간 내에 완료하는 것을 목표로 합니다. - -### `json-server`로 가짜 서버 띄워 활용하기 - -연습용 앱이기 때문에 [`json-server`](https://github.com/typicode/json-server)를 활용해 간단한 가짜 REST API를 구축해 사용합니다. - -- `npm run server`를 실행합니다. (혹은 `npx json-server db.json` 를 직접 실행해도 상관없습니다) -- `GET http://localhost:3000/restaurants`으로 `db.json`에 있는 레스토랑 목록을 불러올 수 있습니다. - -```javascript -// GET 예시 -const response = await fetch("http://localhost:3000/restaurants"); - -// POST 예시 -const response = await fetch("http://localhost:3000/restaurants", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(restaurant), -}); -``` - -## 🔗 참고 문서 - -- [Synchronizing with Effects](https://react.dev/learn/synchronizing-with-effects) - > Effects let you specify side effects that are caused by rendering itself, rather than by a particular event. - - [API Reference: useEffect](https://react.dev/reference/react/useEffect) - > useEffect is a React Hook that lets you synchronize a component with an external system. -- [API Reference: useSate > updater function](https://react.dev/reference/react/useState#updating-state-based-on-the-previous-state) - > `set` function에 함수를 넘겨주면 `updater function`으로 동작합니다. 함수가 아닌 값을 넘겨줄 때와 어떻게 다른지 알아보세요. - -구현을 다 해본 뒤에 Introduction에서 살펴보았던 설계 원칙과 관련해 조금 더 학습해보고 싶다면 아래 문서들도 추가로 확인해 보세요. - -- [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect) - > You do need Effects to synchronize with external systems. - > In React, data flows from the parent components to their children. -- [Components and Hooks must be pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) - > Purity in Components and Hooks is a key rule of React that makes your app predictable, easy to debug, and allows React to automatically optimize your code. - > Side effects should not run in render, as React can render components multiple times to create the best possible user experience. - > One important principle in React is local reasoning: the ability to understand what a component or hook does by looking at its code in isolation. Hooks should be treated like “black boxes” when they are called. diff --git a/README.md b/README.md index 0a708d8..4c47c42 100644 --- a/README.md +++ b/README.md @@ -1,346 +1,180 @@ -# Self-Paced React Step 5 +# styled-components를 적용해서 리팩토링하기 ## 🎯 개인 목표 및 목표 달성을 위한 행동 가이드 이번 미션을 통해 다음과 같은 학습 경험들을 쌓는 것을 목표로 한다. -**1. side effect와 useEffect 이해** - -컴포넌트 렌더링 자체가 아닌, 외부 시스템과의 동기화가 side effect임을 이해하고, -왜 useEffect 안에서 처리해야 하는지 설명할 수 있게 된다. - -**2. fetch를 통한 API 연동 흐름 이해** - -GET 요청으로 목록을 불러와 state에 저장하고, -POST 요청 후 목록을 다시 불러오는 전체 흐름을 직접 구현한다. - -**3. useEffect 의존성 배열 이해** - -빈 배열(`[]`)과 값이 있는 배열의 차이를 이해하고, -effect가 언제 실행되는지 의도적으로 제어할 수 있게 된다. +- styled-components의 기본 문법과 사용법을 익히고, CSS-in-JS 방식이 기존 별도 CSS 파일 방식과 어떤 차이가 있는지 직접 체감한다. +- 단순히 동작하는 코드를 넘어, 컴포넌트마다 스코프가 격리된 스타일을 작성하는 습관을 형성한다. +- styled-components를 처음 접하더라도 공식 문서를 스스로 찾아 읽고 적용하는 자기주도 학습 역량을 키운다. +- CSS 파일 방식 vs CSS-in-JS 방식의 trade-off를 정리해 PR에 나만의 언어로 서술한다. ## 📝 기능 구현 목록 -**1. API로 레스토랑 목록 불러오기** - -- 앱 마운트 시 GET 요청으로 레스토랑 목록을 불러온다. - -**2. 레스토랑 추가 시 POST 요청** - -- 추가하기 버튼 클릭 시 POST 요청을 보내고, 완료 후 목록을 다시 불러온다. +- `styled-components` 패키지 설치 +- 모든 컴포넌트의 CSS Module 파일을 제거하고 styled-components로 전환 + - `Header`, `CategoryFilter`, `RestaurantList` + - `Modal`, `AddRestaurantModal`, `RestaurantDetailModal` +- `props`를 활용한 조건부 스타일링 적용 (`$required`, `$primary`) +- `App.css`에서 Typography 유틸리티 클래스 제거 (각 컴포넌트 스타일로 이동) ## 📚 학습 내용 -### 1. side effect - -컴포넌트 함수는 순수해야 한다. 동일한 props/state를 받으면 항상 동일한 UI를 반환해야 하고, 렌더링 중에 외부에 영향을 주어서는 안 된다. API 호출, DOM 직접 조작, 타이머 설정처럼 외부 시스템과 상호작용하는 작업을 side effect라 한다. - -컴포넌트 함수는 렌더링할 때마다 실행된다. 거기에 API 호출을 직접 넣으면 렌더링될 때마다 요청이 날아가버린다. 그래서 side effect는 렌더링 함수 본문이 아닌, `useEffect`를 통해 렌더링 이후에 실행되도록 분리해야 한다. - -### 2. useEffect와 useCallback - -두 훅 모두 의존성 배열을 사용하지만 역할이 다르다. - -| 훅 | 역할 | 실행 시점 | -|---|---|---| -| `useEffect` | side effect 실행 | 의존성이 바뀔 때마다 안의 코드 실행 | -| `useCallback` | 함수 참조 유지 | 의존성이 바뀔 때만 함수를 새로 만들고, 그 외엔 이전 참조 반환 | - -**useEffect** - -외부 시스템과 동기화할 때 사용한다. 렌더링 이후 실행되며, 의존성 배열로 실행 시점을 제어한다. - -| 의존성 배열 | 실행 시점 | -|---|---| -| 없음 | 매 렌더링마다 | -| `[]` | 마운트 시 한 번 | -| `[value]` | 마운트 + value 변경 시 | - -**왜 같이 쓰는가** - -컴포넌트가 리렌더링될 때마다 함수는 새로 만들어져 참조(주소)가 달라진다. `useEffect` 의존성 배열에 함수를 넣으면, 리렌더링마다 참조가 바뀌어 effect가 반복 실행되는 무한루프가 생긴다. - -```js -// 리렌더링마다 새 참조 → 무한루프 -const fetchRestaurants = async () => { ... }; // 매번 0x001, 0x002... -useEffect(() => { fetchRestaurants(); }, [fetchRestaurants]); -``` - -`useCallback`으로 감싸면 의존성이 바뀌지 않는 한 같은 참조를 반환해 루프가 끊긴다. +### 1. styled-components 기본 문법 -```js -const fetchRestaurants = useCallback(async () => { - const data = await getRestaurants(); - setNewRestaurants(data); -}, []); // 의존성 없음 → 항상 같은 참조 - -useEffect(() => { - void fetchRestaurants(); -}, [fetchRestaurants]); // 참조가 안 바뀌니 최초 1번만 실행 -``` - -**useCallback 의존성 배열** +- `styled.태그명` 뒤에 백틱으로 CSS를 작성하면 해당 태그에 스타일이 적용된 React 컴포넌트가 만들어진다. +- 백틱 안에서 자식 요소 선택자(`label { }`, `input { }`)를 중첩해서 쓸 수 있다. styled-components가 런타임에 고유 클래스명(예: `.sc-abc123`)을 생성하고, 중첩 선택자를 `.sc-abc123 input { }` 형태로 변환하기 때문이다. +- `&`는 생성된 클래스명 자신을 가리키는 선택자로, `&:hover`, `&:last-child` 같은 의사 클래스에 사용한다. -"이 함수가 읽는 값"을 넣는다. 함수 안에서 바뀔 수 있는 값을 참조하면 그 값이 의존성이 된다. +### 2. Scoped Styling 원리 -```js -// [] — 외부 값을 읽지 않으므로 항상 같은 참조 -const fetchRestaurants = useCallback(async () => { - const data = await getRestaurants(); - setNewRestaurants(data); -}, []); - -// [category] — category가 바뀌면 함수를 새로 만들어야 함 -const fetchByCategory = useCallback(async () => { - const data = await getRestaurants(category); - setNewRestaurants(data); -}, [category]); -``` +- 런타임에 컴포넌트마다 고유 클래스명을 생성해 `