Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jeonggoncho/react-practice-diary

๐Ÿ“• React๋ฅผ ์ด์šฉํ•˜์—ฌ ์ œ์ž‘ํ•œ 'Diary ํด๋ก ์ฝ”๋”ฉ'์ž…๋‹ˆ๋‹ค.
https://github.com/jeonggoncho/react-practice-diary

clone-coding javascript jsx react

Last synced: 5 days ago
JSON representation

๐Ÿ“• React๋ฅผ ์ด์šฉํ•˜์—ฌ ์ œ์ž‘ํ•œ 'Diary ํด๋ก ์ฝ”๋”ฉ'์ž…๋‹ˆ๋‹ค.

Awesome Lists containing this project

README

        

# ์ผ๊ธฐ์žฅ

๋ณธ ํ”„๋กœ์ ํŠธ๋Š” ["ํ•œ์ž… ํฌ๊ธฐ๋กœ ์ž˜๋ผ ๋จน๋Š” ๋ฆฌ์•กํŠธ ๊ฐ•์˜"](https://www.udemy.com/course/winterlood-react-basic/)์˜ "์ผ๊ธฐ์žฅ ๋งŒ๋“ค์–ด ๋ณด๊ธฐ"๋ฅผ ํด๋ก ํ•œ ํ”„๋กœ์ ํŠธ๋กœ "๋ฆฌ์•กํŠธ"์˜ ๊ธฐ์ดˆ ์ง€์‹์„ ํ•™์Šตํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œํ•˜์˜€์Šต๋‹ˆ๋‹ค.


## ๋ชฉ์ฐจ

1. [React์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ - useState](#1-react์—์„œ-์‚ฌ์šฉ์ž-์ž…๋ ฅ-์ฒ˜๋ฆฌ---usestate)
2. [React์—์„œ DOM ์กฐ์ž‘ํ•˜๊ธฐ - useRef](#2-react์—์„œ-dom-์กฐ์ž‘ํ•˜๊ธฐ---useref)
3. [React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ1 - ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง(์กฐํšŒ)](#3-react์—์„œ-๋ฆฌ์ŠคํŠธ-์‚ฌ์šฉํ•˜๊ธฐ1---๋ฆฌ์ŠคํŠธ-๋ Œ๋”๋ง์กฐํšŒ)
4. [React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ2 - ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€](#4-react์—์„œ-๋ฆฌ์ŠคํŠธ-์‚ฌ์šฉํ•˜๊ธฐ2---๋ฐ์ดํ„ฐ-์ถ”๊ฐ€)
5. [React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ3 - ๋ฐ์ดํ„ฐ ์‚ญ์ œ](#5-react์—์„œ-๋ฆฌ์ŠคํŠธ-์‚ฌ์šฉํ•˜๊ธฐ3---๋ฐ์ดํ„ฐ-์‚ญ์ œ)
6. [React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ4 - ๋ฐ์ดํ„ฐ ์ˆ˜์ •](#6-react์—์„œ-๋ฆฌ์ŠคํŠธ-์‚ฌ์šฉํ•˜๊ธฐ4---๋ฐ์ดํ„ฐ-์ˆ˜์ •)
7. [React Lifecycle ์ œ์–ดํ•˜๊ธฐ - useEffect](#7-react-lifecycle-์ œ์–ดํ•˜๊ธฐ---useeffect)
8. [React์—์„œ API ํ˜ธ์ถœํ•˜๊ธฐ](#8-react์—์„œ-api-ํ˜ธ์ถœํ•˜๊ธฐ)
9. [์ตœ์ ํ™”1 ์—ฐ์‚ฐ ๊ฒฐ๊ณผ ์žฌ์‚ฌ์šฉ - useMemo](#9-์ตœ์ ํ™”1-์—ฐ์‚ฐ-๊ฒฐ๊ณผ-์žฌ์‚ฌ์šฉ---usememo)
10. [์ตœ์ ํ™”2 ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ - React.memo](#10-์ตœ์ ํ™”2-์ปดํฌ๋„ŒํŠธ-์žฌ์‚ฌ์šฉ---reactmemo)
11. [์ตœ์ ํ™”3 ์ปดํฌ๋„ŒํŠธ & ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ - useCallback](#11-์ตœ์ ํ™”3-์ปดํฌ๋„ŒํŠธ--ํ•จ์ˆ˜-์žฌ์‚ฌ์šฉ---usecallback)
12. [์ตœ์ ํ™”4 - React.memo + useCallback](#12-์ตœ์ ํ™”4---reactmemo--usecallback)
13. [๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง ๋ถ„๋ฆฌํ•˜๊ธฐ - useReducer](#13-๋ณต์žกํ•œ-์ƒํƒœ-๊ด€๋ฆฌ-๋กœ์ง-๋ถ„๋ฆฌํ•˜๊ธฐ---usereducer)
14. [์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์— ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰ํ•˜๊ธฐ - Context](#14-์ปดํฌ๋„ŒํŠธ-ํŠธ๋ฆฌ์—-๋ฐ์ดํ„ฐ-๊ณต๊ธ‰ํ•˜๊ธฐ---context)




## ํ•™์Šต๋‚ด์šฉ

- ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฐ ๋ฐฐ์—ด ๋ฆฌ์ŠคํŠธ ์ฒ˜๋ฆฌํ•˜๊ธฐ
- React Lifecycle๊ณผ API
- React App ํ”„๋กœ์ฒ˜๋Ÿผ ์„ฑ๋Šฅ ์ตœ์ ํ™”ํ•˜๊ธฐ with ๋„๊ตฌ ์‚ฌ์šฉ
- React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์— ์ „์—ญ ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰ํ•˜๊ธฐ




## 1. React์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ - useState

### 1-1. ์‚ฌ์ „ ์ค€๋น„

- `npx create-react-app emotional_diary` ์ž…๋ ฅ์œผ๋กœ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
- ํ”„๋กœ์ ํŠธ ํด๋”์˜ ์ปจํ…์ธ ๋“ค์„ ํ•œ ๋‹จ๊ณ„ ์ƒ์œ„ ํด๋”๋กœ ์ด๋™์‹œํ‚ค๊ณ  ๊ธฐ์กด ์ƒ์„ฑ ํด๋” ์‚ญ์ œ
- ์ž˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํŒŒ์ผ๋“ค ์ •๋ฆฌ (logo.svg, App.test.js, reactWebVitals.js, setupTest.js)


### 1-2. ๋ชฉํ‘œ

![๋‹ค์–‘ํ•œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ](./README_img/๋‹ค์–‘ํ•œ_์‚ฌ์šฉ์ž_์ž…๋ ฅ_์ฒ˜๋ฆฌํ•˜๊ธฐ.png)

- `DiaryEditor`๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ
- ํ•œ ์ค„ ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ (input)
- ์—ฌ๋Ÿฌ ์ค„ ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ (textarea)
- ์„ ํƒ ๋ฐ•์Šค ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ (select)
- ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ํ•ธ๋“ค๋งํ•˜๊ธฐ


### 1-3. DiaryEditor ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ

![DiaryEditor ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ](./README_img/DiaryEditor_์ปดํฌ๋„ŒํŠธ๊ฐ€_ํ•„์š”ํ•œ_๊ฒƒ.png)

- ์ž‘์„ฑ์ž
- ์ผ๊ธฐ ๋ณธ๋ฌธ
- ๊ฐ์ • ์ ์ˆ˜


### 1-4. ์ž‘์„ฑ์ž ๋ฐ ์ผ๊ธฐ ๋ณธ๋ฌธ ์ž…๋ ฅ๋ฐ›๊ธฐ

### - ์ž‘์„ฑ์ž ์ž…๋ ฅ๋ฐ›๊ธฐ

- useState(์ƒํƒœ)์™€ input ํƒœ๊ทธ ํ™œ์šฉ

```jsx
// ์ž‘์„ฑ์ž ์ž…๋ ฅ๋ฐ›๋Š” ์ฝ”๋“œ

import { useState } from "react";

const [author, setAuthor] = useState("");


{
setAuthor(e.target.value);
}}
/>
;
```

- input ํƒœ๊ทธ์˜ ๊ฐ’์„ useState์˜ author๋กœ ์„ค์ •
- onChange ์†์„ฑ์„ ํ†ตํ•ด ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ
- ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ, ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ด๋ฒคํŠธ ๊ฐ์ฒด e๋ฅผ ๋ณด๋ƒ„
- ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜ setAuthor๊ฐ€ ์ด๋ฒคํŠธ ํƒ€๊ฒŸ ๊ฐ’(e.target.value)๋ฅผ ๋ฐ›์•„ author๋กœ ๋ณด๋ƒ„
- ๋ฐ”๋€ author ๊ฐ’์ด ๋‹ค์‹œ input ํƒœ๊ทธ์˜ value๋กœ ๋“ค์–ด๊ฐ€์„œ ํ™”๋ฉด์— ๋ Œ๋”๋ง๋จ


### - ์ผ๊ธฐ ๋ณธ๋ฌธ ์ž…๋ ฅ ๋ฐ›๊ธฐ

- ์•ž์„  ์ž‘์„ฑ์ž ์ž…๋ ฅ๋ฐ›๊ธฐ์™€ ๋™์ผ
- input ํƒœ๊ทธ ๋Œ€์‹  textarea ํƒœ๊ทธ ํ™œ์šฉ

```jsx
// ์ผ๊ธฐ ๋ณธ๋ฌธ ์ž…๋ ฅ๋ฐ›๋Š” ์ฝ”๋“œ

import { useState } from "react";

const [content, setContent] = useState("");


{
setContent(e.target.value);
}}
/>
;
```

- ์ž‘์„ฑ์ž ์ž…๋ ฅ๊ณผ ์ผ๊ธฐ ๋ณธ๋ฌธ ์ž…๋ ฅ ๋ชจ๋‘ ๋ฌธ์ž์—ด ์ƒํƒœ ๊ฐ’์„ ๊ฐ€์ง
- onChange ์†์„ฑ์„ ์ด์šฉ
- ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜์— e.target.value๋ฅผ ์ „๋‹ฌ


### - ๋น„์Šทํ•œ ๋™์ž‘์˜ State ๋ฌถ๊ธฐ

- ์œ„์˜ ์ž‘์„ฑ์ž ์ž…๋ ฅ, ์ผ๊ธฐ ๋ณธ๋ฌธ ์ž…๋ ฅ๊ณผ ๊ฐ™์ด ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” State๋Š” ๋”ฐ๋กœ ๋‘์ง€ ์•Š๊ณ  ํ•˜๋‚˜์˜ State๋กœ ๋ฌถ์–ด ์ค„ ์ˆ˜ ์žˆ์Œ

```jsx
// State ๋ฌถ๊ธฐ

import { useState } from "react";

const [state, setState] = useState({
author: "",
content: "",
});



{
setState({
...state,
author: e.target.value,
// content: state.content,
});
}}
/>


{
setState({
...state,
// author: state.author,
content: e.target.value,
});
}}
/>

;
```

- ์ดˆ๊ธฐ์— author์˜ ๊ฐ’ ๊ณต๋ฐฑ(""), content๋„ ๊ณต๋ฐฑ("")์ž„
- ์ดํ›„ ๊ฐ’์ด ๋ณ€ํ™”ํ•˜๋ฉด ๋ณ€ํ™”ํ•˜๋Š” ๊ฐ’์€ e.target.value๋กœ ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ๋ณ€ํ™”ํ•œ ๊ฐ’์„ ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜์— ์ „๋‹ฌ
- ๊ฐ™์ด ๋ฌถ์—ฌ์žˆ์ง€๋งŒ ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์€ ๊ฐ’์€ state.(์›๋ž˜ ๊ฐ’)์œผ๋กœ ํ•จ๊ป˜ ๊ฐ์ฒด๋กœ ์ „๋‹ฌ
- ํ•˜์ง€๋งŒ ๋” ๋งŽ์€ ๊ฐ์ฒด๊ฐ€ ํ•˜๋‚˜์˜ State์— ๋ฌถ์—ฌ์žˆ์„ ๊ฒฝ์šฐ, ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์Œ
- ๋”ฐ๋ผ์„œ Spread ์—ฐ์‚ฐ์ž(...)๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฐ”๋€Œ๋Š” ๊ฐ’ ์™ธ์—๋Š” ...state๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
- ์ฃผ์˜์‚ฌํ•ญ : ๊ธฐ์กด์˜ ๊ฐ์ฒด(...state)๋ฅผ ์•ž์— ์„œ์ˆ ํ•ด์•ผ ํ•จ
- ๋’ค์— ์„œ์ˆ ํ•  ๊ฒฝ์šฐ, ์—…๋ฐ์ดํŠธ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๊ธฐ์— ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ ๋ฐœ์ƒ


### - onChange ์†์„ฑ ํ•ฉ์น˜๊ธฐ

```jsx
// onChange ์†์„ฑ์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜ ๋ฌถ์–ด๋‚ด๊ธฐ

const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};








;
```

- '[e.target.name]: e.target.value'๋ฅผ ํ†ตํ•ด ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํƒœ๊ทธ๋ฅผ ๊ตฌ๋ถ„ํ•จ


### 1-5. ๊ฐ์ • ์ ์ˆ˜ ์„ ํƒ

- useState์™€ select ํƒœ๊ทธ(+ option ํƒœ๊ทธ)๋ฅผ ํ™œ์šฉ
- ์•ž์„  input๊ณผ textarea์˜ ์†์„ฑ๊ณผ ๋˜‘๊ฐ™์ด ์ ์šฉ๋จ

```jsx
// ์„ ํƒ ์ž…๋ ฅ

const [state, setState] = useState({
author: "",
content: "",
emotion: 1,
});

const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};



1
2
3
4
5

;
```


### 1-6. ์ €์žฅ ๋ฒ„ํŠผ

```jsx
// DiaryEditor.js

const handleSubmit = () => {
console.log(state);
alert("์ €์žฅ ์„ฑ๊ณต");
};


์ผ๊ธฐ ์ €์žฅํ•˜๊ธฐ
;
```

- ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ํด๋ฆญํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— button์˜ onClick ์†์„ฑ์˜ handleSubmit ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰
- ์ฝ˜์†”๋กœ ํ˜„์žฌ ์ž‘์„ฑ๋œ state ๊ฐ์ฒด๋ฅผ ์ถœ๋ ฅ
- alert ๋ฉ”์„œ๋“œ๋กœ ์ €์žฅ ์„ฑ๊ณต ์•Œ๋ฆผ ๋„์šฐ๊ธฐ




## 2. React์—์„œ DOM ์กฐ์ž‘ํ•˜๊ธฐ - useRef

### 2-1. ๋ชฉํ‘œ

- ๋ฆฌ์•กํŠธ์—์„œ DOM ์กฐ์ž‘ํ•˜๊ธฐ
- ์ผ๊ธฐ ์ €์žฅ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์ž‘์„ฑ์ž์™€ ์ผ๊ธฐ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž…๋ ฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
- ์ •์ƒ์ ์ธ ์ž…๋ ฅ ์•„๋‹ˆ๋ผ๋ฉด focusํ•˜๊ธฐ


### 2-2. ์ •์ƒ์ ์ธ ์ž…๋ ฅ์ด ์•„๋‹ ๊ฒฝ์šฐ, alert ๋„์šฐ๊ธฐ

- handleSubmit ์ˆ˜์ •ํ•˜๊ธฐ
- ์กฐ๊ฑด๋ฌธ์œผ๋กœ ์ž‘์„ฑ์ž์™€ ๋ณธ๋ฌธ๋‚ด์šฉ์˜ ๊ธธ์ด์— ๋”ฐ๋ผ alert ๋„์šฐ๊ธฐ
- alert ์‹คํ–‰ ํ›„, ์ดํ›„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๋„๋ก return ์ถ”๊ฐ€

```jsx
// DiaryEditor.js

const handleSubmit = () => {
if (state.author.length < 1) {
alert("์ž‘์„ฑ์ž๋Š” ์ตœ์†Œ 1๊ธ€์ž ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”");
return;
}

if (state.content.length < 5) {
alert("์ผ๊ธฐ ๋ณธ๋ฌธ์€ ์ตœ์†Œ 5๊ธ€์ž ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”");
return;
}

alert("์ €์žฅ ์„ฑ๊ณต");
};
```

- ํ•˜์ง€๋งŒ, ์ž…๋ ฅ์ด ์ •์ƒ์ด ์•„๋‹ˆ๋”๋ผ๋„ `alert`๋ฅผ ๋„์šฐ๋Š” ๊ฒƒ์€ `UX ๊ฒฝํ—˜์ ์œผ๋กœ ์ข‹์ง€ ์•Š์Œ`


### 2-3. ์ •์ƒ์ ์ธ ์ž…๋ ฅ์ด ์•„๋‹ ๊ฒฝ์šฐ, focus ์ฃผ๊ธฐ

- `useRef` ์‚ฌ์šฉ

```jsx
// useRef import ํ•ด์˜ค๊ธฐ
import {useRef, useState} from "react";

// useRef ์‚ฌ์šฉํ•˜์—ฌ DOM ์š”์†Œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ ๋ถ€์—ฌ
const authorInput = useRef();
const contentInput = useRef();

// ์กฐ๊ฑด๋ฌธ์— ๋”ฐ๋ผ ๋ถˆ๋งŒ์กฑ ์‹œ, ํ•ด๋‹น ํ˜„์žฌ์š”์†Œ์— focusํ•˜๊ธฐ
const handleSubmit = () => {
if (state.author.length < 1) {
authorInput.current.focus();
return;
}

if (state.content.length < 5) {
contentInput.current.focus();
return;
}

alert("์ €์žฅ ์„ฑ๊ณต");
};







```

- useRef()๋ฅผ ์ง€์ •ํ•˜๋ฉด ํ•ด๋‹น ๋ณ€์ˆ˜๋Š” `mutableRefObject`๊ฐ€ ๋จ
- mutableRefObject : HTML DOM ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ


![๋ฆฌ์•กํŠธ DOM ์กฐ์ž‘](README_img/๋ฆฌ์•กํŠธ_DOM_์กฐ์ž‘ํ•˜๊ธฐ.gif)

<๋ฆฌ์•กํŠธ DOM ์กฐ์ž‘ ๊ฒฐ๊ณผ>




## 3. React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ1 - ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง(์กฐํšŒ)

### 3-1. ๋ชฉํ‘œ

- `DiaryList` ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ
- `๋ฐฐ์—ด`์„ ์ด์šฉํ•˜์—ฌ list ๋ Œ๋”๋ง ํ•ด๋ณด๊ธฐ
- ๊ฐœ๋ณ„์ ์ธ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค์–ด๋ณด๊ธฐ


### 3-2. ๋”๋ฏธ๋ฐ์ดํ„ฐ ๋งŒ๋“ค๊ณ  ๋ฆฌ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ์— props๋กœ ๋ณด๋‚ด๊ธฐ

```jsx
// App.js

const dummyList = [
{
id: 1,
author: "์กฐ์ •๊ณค",
content: "ํ•˜์ด~1",
emotion: 5,
created_date: new Date().getTime(),
},
{
id: 2,
author: "๊น€์ฒ ์ˆ˜",
content: "ํ•˜์ด~2",
emotion: 2,
created_date: new Date().getTime(),
},
{
id: 3,
author: "์ด์˜์ˆ˜",
content: "ํ•˜์ด~3",
emotion: 3,
created_date: new Date().getTime(),
},
];




;
```

- `dummyList ๋ฐฐ์—ด`์— ๋ฐ์ดํ„ฐ(id, ์ž‘์„ฑ์ž, ๋‚ด์šฉ, ๊ฐ์ •์ ์ˆ˜, ์ƒ์„ฑ์‹œ๊ฐ„)๋ฅผ `๊ฐ์ฒดํƒ€์ž…`์œผ๋กœ ๋‹ด์•„ ๋งŒ๋“ค๊ธฐ
- `DiaryList` ์ปดํฌ๋„ŒํŠธ์— diaryList ์†์„ฑ์œผ๋กœ dummyList ๋ฐฐ์—ด props๋กœ ๋ณด๋‚ด๊ธฐ


```jsx
// DiaryList.js

const DiaryList = ({ diaryList }) => {
return (


์ผ๊ธฐ ๋ฆฌ์ŠคํŠธ


{diaryList.length}๊ฐœ์˜ ์ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.



{diaryList.map((it, idx) => (

์ž‘์„ฑ์ž : {it.author}

์ผ๊ธฐ : {it.content}

๊ฐ์ • : {it.emotion}

์ž‘์„ฑ ์‹œ๊ฐ„(ms) : {it.created_date}


))}


);
};

DiaryList.defaultProps = {
diaryList: [],
};

export default DiaryList;
```

- DiaryList ์ปดํฌ๋„ŒํŠธ์—์„œ diaryList๋ฅผ props๋กœ ๋ฐ›๊ธฐ
- `map ๋ฉ”์„œ๋“œ`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ์ƒ์„ฑ
- map ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ๋ฐฐ์—ด ์ˆœํšŒํ•˜์—ฌ ๊ฐ์ฒด ๋ฐ์ดํ„ฐ ๊ฐ๊ฐ์˜

ํƒœ๊ทธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ตœ์ƒ์œ„
ํƒœ๊ทธ์— ๋‹ด๊ธฐ
- ์ด ๊ฒฝ์šฐ, ์ƒ์„ฑ๋œ ๋ฐฐ์—ด ๊ฐ„์— ํ‚ค๊ฐ€ ์ง€์ •๋˜์–ด์žˆ์ง€ ์•Š์•„ ์ฝ˜์†” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ
- ๋”ฐ๋ผ์„œ ์ตœ์ƒ์œ„
์š”์†Œ์— `key ์†์„ฑ`์— ๊ฐ๊ฐ์˜ ๋ฐฐ์—ด์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” `id`๋ฅผ ๋„ฃ์–ด ์—๋Ÿฌ ํ•ด๊ฒฐ
- ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ `๋‘ ๋ฒˆ์งธ ์ธ์ž์ธ ์ธ๋ฑ์Šค(idx)`๋ฅผ ๋ฐ›์•„ id ๋Œ€์‹  key ์†์„ฑ์— ๋„ฃ์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
- ํ•˜์ง€๋งŒ ์ถ”ํ›„ ์ˆœ์„œ๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ, ์ˆ˜์ • ๋ฐ ์‚ญ์ œ์˜ ๋™์ž‘ ์‹œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด id๊ฐ€ ๊ฐ์ฒด์— ์žˆ๋‹ค๋ฉด id๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ง€ํ–ฅํ•จ
- map ๋ฉ”์„œ๋“œ ์•ˆ์˜ ์š”์†Œ๋Š” ๊ณ„์† ๋ฐ˜๋ณต๋˜๋Š” ์š”์†Œ๋กœ ๋…๋ฆฝ์ ์ธ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ


### 3-3. ๋ฆฌ์ŠคํŠธ์˜ ์•„์ดํ…œ์„ ๊ด€๋ฆฌํ•  ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ

```jsx
// DiaryList.js

import DiaryItem from "./DiaryItem";

const DiaryList = ({ diaryList }) => {
return (


์ผ๊ธฐ ๋ฆฌ์ŠคํŠธ


{diaryList.length}๊ฐœ์˜ ์ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.



{diaryList.map((it, idx) => (

))}


);
};
```

- DiaryItem ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ›์•„ ์ฝœ๋ฐฑํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ
- ๋™์ผํ•˜๊ฒŒ `key ์†์„ฑ`์œผ๋กœ `id ๊ฐ’`์„ ์‚ฌ์šฉํ•˜๊ณ , ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ `Spread ์—ฐ์‚ฐ์ž(...)`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `props`๋กœ ๋ณด๋‚ด๊ธฐ


```jsx
// DiaryItem.js

const DiaryItem = ({ author, content, created_date, emotion, id }) => {
return (




์ž‘์„ฑ์ž : {author} | ๊ฐ์ •์ ์ˆ˜ : {emotion}



{new Date(created_date).toLocaleString()}

{content}


);
};

export default DiaryItem;
```

- `DiaryItem` ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ
- props๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์†Œ์— ๋‹ด์•„ ์ถœ๋ ฅ


![๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง](README_img/๋ฆฌ์ŠคํŠธ_๋ฐ์ดํ„ฐ_๋ Œ๋”๋ง.png)

<๋ฆฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ Œ๋”๋ง ์˜ˆ์‹œ ๊ฒฐ๊ณผ>




## 4. React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ2 - ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€

### 4-1. ํ•™์Šต๋ชฉํ‘œ

- ๋ฐฐ์—ด์„ ์ด์šฉํ•œ React์˜ List์— ์•„์ดํ…œ์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•ด๋ณด๊ธฐ


### 4-2. ์ปดํฌ๋„ŒํŠธ & ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ƒ๊ฐํ•ด๋ณด๊ธฐ

![state ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ1](README_img/State_lifting_01.png)

- DiaryEditor ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž‘์„ฑ๋œ ์ผ๊ธฐ ๋‚ด์šฉ์„ DiaryList ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋ง์„ ํ•˜๊ธธ ์›ํ•จ
- ํ•˜์ง€๋งŒ, ๋ฆฌ์•กํŠธ์—์„œ๋Š” `๋™๋“ฑํ•œ ๋ ˆ๋ฒจ`์—์„  `๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ๋ถˆ๊ฐ€๋Šฅ`


![state ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ2](README_img/State_lifting_02.png)

- ๋ฆฌ์•กํŠธ๋Š” `๋‹จ๋ฐฉํ–ฅ`์œผ๋กœ `๋ฐ์ดํ„ฐ`๊ฐ€ ํ๋ฅด๋Š” ํŠน์„ฑ์„ ์ง€๋‹˜


![state ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ3](README_img/State_lifting_03.png)

- ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€๋ชจ์ธ `App ์ปดํฌ๋„ŒํŠธ`์— `[data, setData]์˜ State`๋ฅผ ๋งŒ๋“ฆ
- `DiaryEditor` ์ปดํฌ๋„ŒํŠธ์—๋Š” ์ƒํƒœ ํ•จ์ˆ˜์ธ `setData`๋ฅผ, `DiaryList` ์ปดํฌ๋„ŒํŠธ์—๋Š” ์—…๋ฐ์ดํŠธ๋˜๋Š” `data`๋ฅผ `props`๋กœ ๊ฐ๊ฐ ์ „๋‹ฌ


![state ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ4](README_img/State_lifting_04.png)

- ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์ผ๊ธฐ๊ฐ€ ์ž‘์„ฑ๋  ๋•Œ, DiaryEditor๋Š” ์ƒํƒœ ํ•จ์ˆ˜์ธ setData๋ฅผ ํ˜ธ์ถœ
- ์ƒˆ๋กญ๊ฒŒ ์ž‘์„ฑ๋œ ์ผ๊ธฐ ๋ฐ์ดํ„ฐ๋Š” state์˜ data๋กœ ์ „๋‹ฌ๋จ
- ์ด ์—…๋ฐ์ดํŠธ ๋œ data๋ฅผ DiaryList์—์„œ ๋ฐ›์•„ ๋ฆฌ๋ Œ๋”๋งํ•˜๊ฒŒ ๋จ


![state ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ5](README_img/State_lifting_05.png)

- ์ฆ‰, `๋ฐ์ดํ„ฐ`๋Š” ๋ถ€๋ชจ์—์„œ ์ž์‹, ์ฆ‰, `์œ„์—์„œ ์•„๋ž˜`๋กœ ์ „๋‹ฌ
- ์ž์‹์—์„œ๋Š” ๋ถ€๋ชจ๋กœ ์ƒํƒœ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ์— `์ด๋ฒคํŠธ`๋Š” `์•„๋ž˜์—์„œ ์œ„`๋กœ ์ „๋‹ฌ


### 4-3. State ๋งŒ๋“ค๊ธฐ

### - App ์ปดํฌ๋„ŒํŠธ state ์ƒ์„ฑ

```jsx
// App.js

const [data, setData] = useState([]);

const dataId = useRef(0);

const onCreate = (author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData([newItem, ...data]);
};
```

- ์ด๋ฒคํŠธ onCreate ์ƒ์„ฑ
- useRef()์— ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ 0 ์ง€์ • => <๋ณ€์ˆ˜๋ช…>.current๋กœ ๊ฐ’์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Œ
- ์ด ํ›„ <๋ณ€์ˆ˜๋ช…>.current๋ฅผ 1์”ฉ ์ฆ๊ฐ€์‹œ์ผœ id๋ฅผ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ด
- ์ƒˆ๋กœ ์ž‘์„ฑ๋œ ์ผ๊ธฐ๋‚ด์šฉ์„ ๊ธฐ์กด ๋‚ด์šฉ๋“ค์˜ ์•ž์— ์œ„์น˜์‹œํ‚ด


### - props๋กœ ์ด๋ฒคํŠธ์™€ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

```jsx
// App.js





```

- DiaryEditor๋กœ onCreate ํ•จ์ˆ˜ ์ „๋‹ฌ
- DiaryList๋กœ data ์ „๋‹ฌ


### - ์ด๋ฒคํŠธ ๋ฐ›๊ธฐ

```jsx
// DiaryEditor.js

const DiaryEditor = ({ onCreate }) => {...}
```

- props๋กœ ์ „๋‹ฌ๋œ onCreate ๋ฐ›๊ธฐ


### - ์ผ๊ธฐ๋ฅผ ์ œ์ถœํ•˜๋ฉด ์ด๋ฒคํŠธ ํ˜ธ์ถœ

```jsx
// DiaryEditor.js

const handleSubmit = () => {
if (state.author.length < 1) {
authorInput.current.focus();
return;
}

if (state.content.length < 5) {
contentInput.current.focus();
return;
}
onCreate(state.author, state.content, state.emotion);
alert("์ €์žฅ ์„ฑ๊ณต");
setState({
author: "",
content: "",
emotion: 1,
});
};
```

- ์ œ์ถœ(handleSubmit) ์‹œ, onCreate()ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•จ
- ์ธ์ž๋กœ state์˜ author, content, emotion์„ ์ „๋‹ฌ
- ์ €์žฅ ํ›„, ์ž…๋ ฅ ์นธ ๋น„์šฐ๊ณ , ๊ฐ์ • 1๋กœ ์ดˆ๊ธฐํ™”


![state๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ ๊ฒฐ๊ณผ](README_img/state๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ_๋ฐ์ดํ„ฐ_๋ Œ๋”๋ง.gif)




## 5. React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ3 - ๋ฐ์ดํ„ฐ ์‚ญ์ œ

### 5-1. ํ•™์Šต๋ชฉํ‘œ

- ์‚ญ์ œ๋ฒ„ํŠผ์„ ๊ฐ ์ผ๊ธฐ ๋ฆฌ์ŠคํŠธ ๋ชฉ๋ก๋งˆ๋‹ค ์ƒ์„ฑ
- ์‚ญ์ œ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ, ํ™•์ธ ๋ฉ”์‹œ์ง€๊ฐ€ ์ „๋‹ฌ๋˜๊ณ  ํ™•์ธ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ์ผ๊ธฐ ์•„์ดํ…œ์ด ์‚ญ์ œ๋˜๊ณ  ๋ฆฌ๋ Œ๋”๋ง ๋จ


### 5-2. onDelete ํ•จ์ˆ˜ ์ƒ์„ฑ

```jsx
// App.js

// onDelete ํ•จ์ˆ˜
const onDelete = (targetId) => {
console.log(`${targetId}๊ฐ€ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค`);
const newDiaryList = data.filter((it) => it.id !== targetId);
setData(newDiaryList);
};

return (



// DiaryList๋กœ props๋กœ onDelete ์ „๋‹ฌ


);
```

- onDelete ํ•จ์ˆ˜๋Š” ์‚ญ์ œ๋ฒ„ํŠผ๊ณผ ํ•จ๊ป˜ ํ•ด๋‹น ์ผ๊ธฐ ์•„์ดํ…œ์˜ id๊ฐ’์„ targetId์ธ์ž๋กœ ๋ฐ›์Œ
- ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ data์—์„œ id๊ฐ€ ์ธ์ž๋กœ ๋ฐ›์€ targetId์™€ ๊ฐ™์ง€ ์•Š์€ ๋‚˜๋จธ์ง€ ์•„์ดํ…œ๋“ค์„ ๋ชจ์Œ
- ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ๋œ ์ผ๊ธฐ ๋ฆฌ์ŠคํŠธ๋“ค์„ setData() ์ƒํƒœ ํ•จ์ˆ˜์— ๋„ฃ์–ด ์ƒํƒœ ๋ฐ”๊พธ๊ธฐ


### 5-3. DiaryList๋กœ ์ „๋‹ฌ๋œ onDelete ํ•จ์ˆ˜๋ฅผ DiaryItem ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ

```jsx
// DiaryList.js

const DiaryList = ({ onDelete, diaryList }) => {
return (


์ผ๊ธฐ ๋ฆฌ์ŠคํŠธ


{diaryList.length}๊ฐœ์˜ ์ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.



{diaryList.map((it, idx) => (
// DiaryItem์œผ๋กœ onDelete ์ „๋‹ฌ

))}


);
};
```

- onDelete ํ•จ์ˆ˜๋ฅผ DiaryItem ์ปดํฌ๋„ŒํŠธ๋กœ props๋กœ ์ „๋‹ฌ


### 5-4. ์‚ญ์ œ ์‹œ, onDelete ํ•จ์ˆ˜ ํ˜ธ์ถœํ•˜๊ณ  ํ•ด๋‹น ์•„์ดํ…œ์˜ id๊ฐ’ ์ „๋‹ฌ

```jsx
// DiaryItem.js

// onDelete ํ•จ์ˆ˜ ์ „๋‹ฌ ๋ฐ›์Œ
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
return (


// ...
{
console.log(id);
if (window.confirm(`${id}๋ฒˆ์งธ ์ผ๊ธฐ๋ฅผ ์ •๋ง ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`)) {
onDelete(id);
}
}}
>
์‚ญ์ œํ•˜๊ธฐ


);
};
```

- onClick์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ง€์ •
- `window.confirm()` : ํ™•์ธ ๋ฉ”์‹œ์ง€ ๋„์šฐ๊ธฐ
- ํ™•์ธ ํด๋ฆญ(true)์ผ ๊ฒฝ์šฐ, `onDelete` ํ•จ์ˆ˜ ํ˜ธ์ถœํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•ด๋‹น ์ผ๊ธฐ ์•„์ดํ…œ์˜ id ์ „๋‹ฌ
- ์ทจ์†Œ ํด๋ฆญ(false)์ผ ๊ฒฝ์šฐ, ์•„๋ฌด ์ผ๋„ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ


![๋ฆฌ์ŠคํŠธ ์‚ญ์ œ ๊ฒฐ๊ณผ](README_img/๋ฆฌ์ŠคํŠธ_๋ฐ์ดํ„ฐ_์‚ญ์ œํ•˜๊ธฐ.gif)

<๋ฆฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์‚ญ์ œ ์˜ˆ์‹œ ๊ฒฐ๊ณผ>




## 6. React์—์„œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉํ•˜๊ธฐ4 - ๋ฐ์ดํ„ฐ ์ˆ˜์ •

### 6-1. ์ˆ˜์ •ํ•˜๊ธฐ ๊ธฐ๋Šฅ์—์„œ ํ•„์š”ํ•œ ๊ฒƒ

- ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ
- ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ธฐ์กด ๋‚ด์šฉ์ด ์ˆ˜์ •ํผ์œผ๋กœ ๋ณ€ํ™˜
- ํŠน์ • ๊ธ€์ž ์ˆ˜๋ฅผ ์ถฉ์กฑ ์‹œ, ์ˆ˜์ • ์™„๋ฃŒ๋˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ, ์ˆ˜์ •ํผ์— ํฌ์ปค์Šค ๋˜๋„๋ก ํ•˜๊ธฐ


### 6-2. isEdit์˜ ์ƒํƒœ์— ๋”ฐ๋ฅธ ๋ฒ„ํŠผ๊ณผ ์ผ๊ธฐ๋‚ด์šฉ ๋ณ€ํ™˜

### - ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ

```jsx
// DiaryItem.js

์‚ญ์ œํ•˜๊ธฐ
์ˆ˜์ •ํ•˜๊ธฐ
```

- ๊ธฐ์กด ์‚ญ์ œํ•˜๊ธฐ ๋ฒ„ํŠผ๊ณผ ํ•จ๊ป˜ ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ
- ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, toggleIsEdit ํ•จ์ˆ˜ ์‹คํ–‰


### - state์™€ toggleIsEdit

```jsx
// DiaryItem.js

const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
```

- `isEdit`์ด๋ž€ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ณ  state๋กœ ๊ธฐ๋ณธ ๊ฐ’์„ `false`๋กœ ์ง€์ •
- toggleIsEdit์€ ์ƒํƒœ ํ•จ์ˆ˜ setIsEdit์˜ ์ธ์ž๋กœ `!isEdit`์„ ๋‘์–ด isEdit์ด false๋ฉด true๋กœ, true๋ฉด false๋กœ `๋ฐ˜์ „`๋˜๋„๋ก ํ•จ(์Šค์œ„์น˜)
- true๋Š” ์ˆ˜์ •์ƒํƒœ, false๋Š” ๋น„ ์ˆ˜์ •์ƒํƒœ
- ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ์˜ onClick์— toggleIsEdit ์ง€์ •


### - ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•œ ์ผ๊ธฐ๋‚ด์šฉ, ์ˆ˜์ •ํผ, ๋ฒ„ํŠผ ๋ณ€ํ™˜

```jsx
// DiaryItem.js

const [localContent, setLocalContent] = useState(content);

...


{isEdit ? (
{
setLocalContent(e.target.value);
}}
/>
) : (
<>{content}>
)}

{isEdit ? (
<>
์ˆ˜์ • ์ทจ์†Œ
์ˆ˜์ • ์™„๋ฃŒ
>
) : (
<>
์‚ญ์ œํ•˜๊ธฐ
์ˆ˜์ •ํ•˜๊ธฐ
>
)}
```

- ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ isEdit์ด true, ์ฆ‰ ์ˆ˜์ •์ƒํƒœ์ด๋ฉด, textarea ์š”์†Œ๊ฐ€ ์ƒ๊น€
- ์ˆ˜์ •ํผ textarea์˜ ๋‚ด์šฉ์€ ๋ณ€์ˆ˜ localContent๋กœ ์ง€์ •ํ•˜๊ณ  state๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `์ดˆ๊ธฐ ๊ฐ’`์„ ๊ธฐ์กด์— ์ž‘์„ฑ๋˜์–ด์žˆ๋˜ `์ผ๊ธฐ ๋‚ด์šฉ์ธ content`๋กœ ์„ค์ •
- ๋ฒ„ํŠผ์˜ ๊ฒฝ์šฐ์—๋„ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ isEdit์ด true, ์ฆ‰ ์ˆ˜์ •์ƒํƒœ์ด๋ฉด `์ˆ˜์ • ์ทจ์†Œ`, `์ˆ˜์ • ์™„๋ฃŒ` ๋ฒ„ํŠผ์„ ๋ณด์—ฌ์ฃผ๊ณ , false๋กœ ์ˆ˜์ •์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ฉด ๊ธฐ์กด์˜ `์‚ญ์ œํ•˜๊ธฐ` ๋ฐ `์ˆ˜์ •ํ•˜๊ธฐ` ๋ฒ„ํŠผ์ด ๋ณด์ด๋„๋ก ํ•จ


### 6-3. ๋ฒ„ํŠผ์˜ onClick ์„ค์ • ๋ฐ ๋ฐ์ดํ„ฐ ์ด๋ฒคํŠธ ํ•จ์ˆ˜ ์ž์‹์œผ๋กœ ์ „๋‹ฌ

### - onClick ์„ค์ •

```jsx
// DiaryItem.js

// textarea์˜ DOM ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋„๋ก localContentInput ์ƒ์„ฑ
const localContentInput = useRef();

// ์ˆ˜์ • ์™„๋ฃŒ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์‹คํ–‰๋˜๋Š” hadleEdit ํ•จ์ˆ˜
const handleEdit = () => {
if (localContent.length < 5) {
localContentInput.current.focus();
return;
}
if (window.confirm(`${id}๋ฒˆ์งธ ์ผ๊ธฐ๋ฅผ ์ˆ˜์ •ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`)) {
onEdit(id, localContent);
toggleIsEdit();
}
};

// ์ˆ˜์ • ์ทจ์†Œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์‹คํ–‰๋˜๋Š” handleQuitEdit ํ•จ์ˆ˜
const handleQuitEdit = () => {
setIsEdit(false);
setLocalContent(content);
};

...

// ๋‚ด์šฉ ์ˆ˜์ • ํผ textarea

// ์ˆ˜์ • ์ทจ์†Œ, ์ˆ˜์ • ์™„๋ฃŒ ๋ฒ„ํŠผ
<>
์ˆ˜์ • ์ทจ์†Œ
์ˆ˜์ • ์™„๋ฃŒ
>
```

- ๋จผ์ € ์ˆ˜์ • ์ทจ์†Œ ๋ฒ„ํŠผ์˜ `handleQuitEdit`์„ ๋ณด๋ฉด, `setIsEdit(false);`์„ ํ†ตํ•ด ์ˆ˜์ •ํ•˜์ง€ ์•Š์Œ์œผ๋กœ ๋ณ€๊ฒฝ
- ๋งŒ์•ฝ, ์ˆ˜์ • ์ค‘์ด์˜€๋‹ค๋ฉด ์ˆ˜์ • ์ทจ์†Œ๋ฅผ ๋ˆ„๋ฅด๊ณ  ๋‹ค์‹œ ์ˆ˜์ •ํ•˜๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ, ์•ž์„  ์ˆ˜์ • ๋‚ด์—ญ์ด ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๊ธฐ์— ์ทจ์†Œ ์‹œ, ์ด๋ฅผ `์ดˆ๊ธฐํ™”`ํ•˜๊ธฐ ์œ„ํ•ด `setLocalContent(content);`์œผ๋กœ ๊ธฐ์กด ์ผ๊ธฐ๋‚ด์šฉ ๋„ฃ๊ธฐ
- ์ˆ˜์ • ์™„๋ฃŒ๋ฅผ ํด๋ฆญํ•˜๋ฉด `handleEdit` ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰ ๋จ
- textarea์— `useRef()`์ธ `localContentInput` ์ง€์ •ํ•˜์—ฌ DOM ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ
- handleEdit ํ•จ์ˆ˜๋Š” ๊ธฐ์กด ์ผ๊ธฐ๋‚ด์šฉ์˜ ๊ทœ์น™์ฒ˜๋Ÿผ 5๊ธ€์ž ๋ฏธ๋งŒ์œผ๋กœ ์ž‘์„ฑ๋œ ๊ฒฝ์šฐ, `focus()` ์ฃผ๊ธฐ
- ํ†ต๊ณผ๋œ ๊ฒฝ์šฐ, ํ™•์ธ ์ฐฝ์„ ๋„์šฐ๊ณ  `onEdit()` ํ•จ์ˆ˜์— id์™€ localContent๋ฅผ ๋ณด๋‚ด ๋ฐ์ดํ„ฐ ์ˆ˜์ •
- toggleIsEdit() ํ•จ์ˆ˜๋กœ ๋‹ค์‹œ ์ˆ˜์ • ํ™œ์„ฑํ™” ์ƒํƒœ ๋‹ซ๊ธฐ


### - App ์ปดํฌ๋„ŒํŠธ์—์„œ onEdit ์ „๋‹ฌํ•˜๊ธฐ

```jsx
// App.js

const onEdit = (targetId, newContent) => {
setData(
data.map((it) =>
it.id === targetId ? { ...it, content: newContent } : it,
),
);
};

...

```

```jsx
// DiaryList.js

const DiaryList = ({ onEdit, onRemove, diaryList }) => {
...

};
```

- onEdit ํ•จ์ˆ˜๋Š” ๋ฐ์ดํ„ฐ์˜ `id`์™€ `์ˆ˜์ •๋œ ๋‚ด์šฉ`์„ ์ „๋‹ฌ๋ฐ›์Œ
- data๋“ค์„ `map`์œผ๋กœ ์ˆœํšŒํ•˜์—ฌ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›์€ id์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์•„ content๋งŒ ์ˆ˜์ •๋œ newContent๋กœ `๋ฎ์–ด์”Œ์›€`
- App ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์„ฑ๋œ onEdit ํ•จ์ˆ˜๋ฅผ DiaryList ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๊ณ  ๋‹ค์‹œ DiaryItem ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•จ


![๋ฆฌ์ŠคํŠธ ์ˆ˜์ • ๊ฒฐ๊ณผ](README_img/๋ฆฌ์ŠคํŠธ_๋ฐ์ดํ„ฐ_์ˆ˜์ •ํ•˜๊ธฐ.gif)

<๋ฆฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ˆ˜์ • ์˜ˆ์‹œ ๊ฒฐ๊ณผ>




## 7. React Lifecycle ์ œ์–ดํ•˜๊ธฐ - useEffect

### 7-1. Lifecycle

- ์ƒ์• ์ฃผ๊ธฐ๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ `์‹œ๊ฐ„์˜ ํ๋ฆ„`์— ๋”ฐ๋ผ ํƒ„์ƒ๋ถ€ํ„ฐ ์ฃฝ์Œ๊นŒ์ง€ ์ด๋ฅด๋Š” `๋‹จ๊ณ„์ ` ๊ณผ์ •
- React์˜ ์ปดํฌ๋„ŒํŠธ ์—ญ์‹œ ์ƒ๋ช…์ฃผ๊ธฐ(Lifecycle)์„ ๊ฐ€์ง
-

![๋ฆฌ์•กํŠธ ๋ผ์ดํ”„์‚ฌ์ดํด](README_img/lifecycle.png)

- React์˜ Lifecycle์€ ํฌ๊ฒŒ 3๊ฐ€์ง€์˜ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰จ
- `ํƒ„์ƒ`(Mount) : ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ
- `๋ณ€ํ™”`(Update) : ์—…๋ฐ์ดํŠธ(๋ฆฌ๋ Œ๋”)
- `์ฃฝ์Œ`(Unmount) : ํ™”๋ฉด์—์„œ ์‚ฌ๋ผ์ง
- ๊ฐ๊ฐ์˜ ๋‹จ๊ณ„๋งˆ๋‹ค `ํŠน์ •ํ•œ ์ž‘์—…`์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Œ


### - Lifecycle ๊ฐ๊ฐ์˜ ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ

- ์ง€๊ธˆ๊นŒ์ง€๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ `ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ`๋งŒ ์ด์šฉํ•ด์™”์Œ
- ํ•˜์ง€๋งŒ, ์ด ๋ฉ”์„œ๋“œ๋“ค์€ `ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ`์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํ•˜๋‹ค.
- `ref`, `state`์˜ ๊ฒฝ์šฐ๋„ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  `ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ`์—์„œ๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.


1. Mount ๋‹จ๊ณ„ : ComponentDidMount()
2. Update ๋‹จ๊ณ„ : ComponentDidUpdate()
3. Unmount ๋‹จ๊ณ„ : ComponentWillUnmount()


### 7-2. React Hooks

- 2019๋…„ 6์›” ์ •์‹ ์ถœ์‹œ๋œ ๊ธฐ๋Šฅ
- ์•ž์„  Lifecycle์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ, state, ref๋ฅผ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” React์—์„œ `์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ค์›€`์ด ์žˆ์—ˆ์Œ
- ๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๊ณ ์ž, `use` ํ‚ค์›Œ๋“œ๋ฅผ ์•ž์— ๋ถ™์—ฌ `ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ`๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ด ๊ธฐ๋Šฅ๋“ค์„ `ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ`์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Hooking(๋‚š์Œ)ํ•œ ๊ฒƒ
- ex) useState, useEffect, useRef, ...


### - ์• ์ดˆ์— React์—์„œ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ด์œ ๋Š”?

- ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ๊ณ  ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Œ
- ์ค‘๋ณต ์ฝ”๋“œ, ๊ฐ€๋…์„ฑ ๋ฌธ์ œ ๋“ฑ ์—ฌ๋Ÿฌ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉ


### 7-3. useEffect

- ์•ž์„  ๊ฐ `Lifecycle์˜ ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ`๋“ค์„ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
- 2๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ธ `์ฝœ๋ฐฑํ•จ์ˆ˜`, `์˜์กด์„ฑ ๋ฐฐ์—ด`์„ ๋ฐ›์Œ

```jsx
// useEffect ์‚ฌ์šฉ

import React, { useEffect } from "react";

useEffect(() => {
// ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ž‘์„ฑ
}, []); // '[]'๋Š” Dependency Array(์˜์กด์„ฑ ๋ฐฐ์—ด) : ์ด ๋ฐฐ์—ด ๋‚ด์— ๋“ค์–ด์žˆ๋Š” ๊ฐ’์ด ๋ณ€ํ™”ํ•˜๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์ˆ˜ํ–‰๋จ
```


### - Mount ๋‹จ๊ณ„์—์„œ ์ž‘์—…์ˆ˜ํ–‰

```jsx
// ์ƒˆ๋กœ ๋งŒ๋“  Lifecycle.js

// Mount ๋‹จ๊ณ„์—์„œ ์ž‘์—…์ˆ˜ํ–‰

import React, { useEffect, useState } from "react";

const Lifecycle = () => {
// Mount ๋‹จ๊ณ„์— ์‹คํ–‰๋จ -> dependency array์— ๋นˆ๋ฐฐ์—ด
useEffect(() => {
console.log("Mount!");
}, []);
}
```

- dependency ๋ฐฐ์—ด์— ์•„๋ฌด ๊ฐ’๋„ ๋„ฃ์ง€ ์•Š์œผ๋ฉด(`๋นˆ๋ฐฐ์—ด`) Mount ๋‹จ๊ณ„์—์„œ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์ˆ˜ํ–‰๋จ


### - Update ๋‹จ๊ณ„์—์„œ ์ž‘์—…์ˆ˜ํ–‰

```jsx
// Lifecycle.js

import React, { useEffect, useState } from "react";

const Lifecycle = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState("");

// Update ๋‹จ๊ณ„์— ์‹คํ–‰๋จ -> dependency array ์—†์• ๊ธฐ: ์–ด๋Š ์š”์†Œ๋ผ๋„ ์—…๋ฐ์ดํŠธ ๋˜๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ˆ˜ํ–‰
useEffect(() => {
console.log("Update!");
});

// ํŠน์ • ์š”์†Œ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ˆ˜ํ–‰
// count์˜ state๊ฐ€ ๋ณ€ํ•˜๋Š” ์ˆœ๊ฐ„ ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ˆ˜ํ–‰
useEffect(() => {
console.log(`count is update : ${count}`);
if (count > 5) {
alert("count๊ฐ€ 5๋ฅผ ๋„˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 1๋กœ ์ดˆ๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค.");
setCount(1);
}
}, [count]);

// text์˜ state๊ฐ€ ๋ณ€ํ•˜๋Š” ์ˆœ๊ฐ„ ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ˆ˜ํ–‰
useEffect(() => {
console.log(`text is update : ${text}`);
}, [text]);
}
```

- `dependency ๋ฐฐ์—ด์„ ์ž์ฒด๋ฅผ ์—†์• ๋ฉด` ์–ด๋Š ์š”์†Œ๋ผ๋„ ์—…๋ฐ์ดํŠธ ๋˜๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ˆ˜ํ–‰
- `dependency ๋ฐฐ์—ด์— ๊ฐ’์„ ๋„ฃ์œผ๋ฉด`, ํ•ด๋‹น ๋ณ€์ˆ˜ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋˜๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ˆ˜ํ–‰


![update](README_img/useEffect_update.gif)


### - Unmount ๋‹จ๊ณ„์—์„œ ์ž‘์—…์ˆ˜ํ–‰

```jsx
// Lifecycle.js

import React, { useEffect, useState } from "react";

const UnmountTest = () => {
// Unmount ๋‹จ๊ณ„์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—…์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜ ์•ˆ์—์„œ
// ํ•จ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•˜๊ฒŒ ํ•˜๋ฉด, Unmount๋˜๋Š” ๊ฒฝ์šฐ, ๋ฆฌํ„ด๋œ ํ•จ์ˆ˜๊ฐ€ ์ˆ˜ํ–‰๋จ
useEffect(() => {
console.log("Mount!");
return () => {
// Unmount ๊ฒฝ์šฐ, ์ˆ˜ํ–‰
console.log("Unmount!");
};
}, []);
return

Unmount Testing Component
;
};
```

- Unmount ๋‹จ๊ณ„์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—…์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” useEffect์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜์— `๋ฆฌํ„ด ํ•จ์ˆ˜๋ฅผ ์ •์˜`ํ•˜๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ Unmount ๋‹จ๊ณ„์—์„œ ์ˆ˜ํ–‰๋จ


![mount, Unmount](README_img/useEffect_mount_unmount.gif)




## 8. React์—์„œ API ํ˜ธ์ถœํ•˜๊ธฐ

### 8-1. ํ•™์Šต๋ชฉํ‘œ

- useEffect๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Mount ์‹œ์ ์— API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ํ•ด๋‹น API ๊ฒฐ๊ณผ ๊ฐ’์„ ์ผ๊ธฐ ๋ฐ์ดํ„ฐ์˜ ์ดˆ๊ธฐ ๊ฐ’์œผ๋กœ ์ด์šฉํ•˜๊ธฐ


### 8-2. fetch๋กœ API ๋ฐ›์•„์˜ค๊ธฐ

```javascript
// App.js

const getData = async () => {
const res = await fetch(
"https://jsonplaceholder.typicode.com/comments",
).then((res) => res.json());
const initData = res.slice(0, 20).map((it) => {
return {
author: it.email,
content: it.body,
emotion: Math.floor(Math.random() * 5) + 1,
created_date: new Date().getTime(),
id: dataId.current++,
};
});

setData(initData);
};
```

- jsonplaceholder(๋”๋ฏธ json์„ ์‘๋‹ตํ•˜๋Š” API)๋ฅผ ํ†ตํ•ด fetch๋กœ API ๋ฐ›๊ธฐ
- .then()์„ ์‚ฌ์šฉํ•˜์—ฌ resolve๋˜๋ฉด, ํ•ด๋‹น ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด
- ํ•˜์ง€๋งŒ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋Š” ํ—ค๋”๋งŒ ์žˆ๊ธฐ์— `.json()`๋กœ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ `Promise ์ƒํƒœ`๋กœ ๋ณ€ํ™˜
- ์ด์ค‘ 20๊ฐœ๋ฅผ sliceํ•˜๊ณ , map์„ ํ†ตํ•ด ๊ฐ๊ฐ์˜ ๊ฐ์ฒด๋ฅผ ๋‹ด์€ ๋ฐฐ์—ด์„ ๋ฆฌํ„ดํ•œ๋‹ค.
- ์ด ๋ฐฐ์—ด์„ `setData`์— ๋‹ด์•„ data๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.


### 8-3. useEffect๋กœ Mount์‹œ ๋ฐ์ดํ„ฐ ํ˜ธ์ถœ

```javascript
// App.js

useEffect(() => {
getData();
}, []);
```

- useEffect๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  dependency ๋ฐฐ์—ด์„ `๋นˆ ๋ฐฐ์—ด`๋กœ ์„ค์ •ํ•˜์—ฌ `Mount ๋‹จ๊ณ„`์—์„œ ํ•ด๋‹น ๋ธ”๋ก์„ ์ˆ˜ํ–‰
- ์•ž์„  API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” getData() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ์‹œํ‚จ๋‹ค.


![API ํ˜ธ์ถœ](README_img/API์‚ฌ์šฉ.gif)

<ํ™”๋ฉด ๋ Œ๋”๋ง ์‹œ, API๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ>




## 9. ์ตœ์ ํ™”1 ์—ฐ์‚ฐ ๊ฒฐ๊ณผ ์žฌ์‚ฌ์šฉ - useMemo

### 9-1. ํ•™์Šต๋ชฉํ‘œ

- ํ˜„์žฌ ์ผ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜๋Š” ํ•จ์ˆ˜์ œ์ž‘
- ์ผ๊ธฐ ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด๊ฐ€ ๋ณ€ํ™”ํ•˜์ง€ ์•Š์„ ๋•Œ, ํ•จ์ˆ˜๊ฐ€ ๊ฐ’์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ
- Memoization ๊ฐœ๋… ์ดํ•ดํ•˜๊ธฐ


### 9-2. Memoization

- ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ• ์ค‘ ํ•˜๋‚˜
- ์ด๋ฏธ ๊ณ„์‚ฐํ•ด๋ณธ `์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์–ต`ํ•ด๋‘๊ณ  ๋™์ผํ•œ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ๊ฒฝ์šฐ, ์—ฐ์‚ฐ์„ `์žฌ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ `, `๊ธฐ์–ตํ•ด๋‘” ๋ฐ์ดํ„ฐ`๋ฅผ ๋ฐ”๋กœ ๋ฐ˜ํ™˜


### 9-3. App ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ, ๊ธฐ๋ถ„ ๋‚˜์œ ์ผ๊ธฐ ๊ณ„์‚ฐ

- ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ 3๊ฐ€์ง€
- ๊ธฐ๋ถ„ ๋‚˜์œ ์ผ๊ธฐ(1~2์ ) ๊ฐœ์ˆ˜
- ๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ(3~5์ ) ๊ฐœ์ˆ˜
- ๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ์˜ ๋น„์œจ


### - ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๋ถ„์„ ํ•จ์ˆ˜ ์ƒ์„ฑ

```javascript
// App.js

const getDiaryAnalysis = () => {
console.log("์ผ๊ธฐ ๋ถ„์„ ์‹œ์ž‘");

const goodCount = data.filter((it) => it.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100;
return { goodCount, badCount, goodRatio };
};

const { goodCount, badCount, goodRatio } = getDiaryAnalysis();
```

- getDiaryAnalysis ํ•จ์ˆ˜ ์ƒ์„ฑํ•˜๊ณ , ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ฝ˜์†”์— "์ผ๊ธฐ ๋ถ„์„ ์‹œ์ž‘"์„ ์ถœ๋ ฅํ•œ๋‹ค.
- goodCount๋Š” data ๋ฐฐ์—ด์—์„œ ๊ฐ์ฒด์˜ emotion ๊ฐ’์ด 3์ด์ƒ์ธ ๊ฒƒ๋งŒ ํ•„ํ„ฐ๋กœ ๋ชจ์•„ length๋กœ ๊ฐœ์ˆ˜๋ฅผ ์ง€์ •
- badCount๋Š” ์ „์ฒด ์ผ๊ธฐ ๊ฐœ์ˆ˜ data.length์—์„œ goodCount๋ฅผ ๋บ€ ๋‚˜๋จธ์ง€ ๊ฐœ์ˆ˜
- goodRatio๋Š” ์ „์ฒด ์ผ๊ธฐ ๊ฐœ์ˆ˜์—์„œ ์ข‹์€ ์ผ๊ธฐ ๊ฐœ์ˆ˜๋ฅผ ๋‚˜๋ˆ„๊ณ  100์„ ๊ณฑํ•œ ๋น„์œจ
- ์ตœ์ข…์ ์œผ๋กœ getDiaryAnalysis ํ•จ์ˆ˜๋Š” 3๊ฐœ์˜ ์ƒ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•จ
- ๋น„๊ตฌ์กฐํ™” ํ• ๋‹น์„ ํ†ตํ•ด ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ, ๊ฐ๊ฐ์˜ ์ƒ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ


### - ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ

```javascript
// App.js


...
์ „์ฒด ์ผ๊ธฐ : {data.length}

๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๊ฐœ์ˆ˜ : {goodCount}

๊ธฐ๋ถ„ ๋‚˜์œ ์ผ๊ธฐ ๊ฐœ์ˆ˜ : {badCount}

๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๋น„์œจ : {goodRatio}

...

```

- ๊ฐ๊ฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.
- ์ฝ˜์†”์„ ๋ณด๋ฉด "์ผ๊ธฐ ๋ถ„์„ ์‹œ์ž‘"์„ 2๋ฒˆ ์ถœ๋ ฅํ•˜๋Š”๋ฐ ์ด ์ด์œ ๋Š” ์ฒ˜์Œ์— data์— ์•„๋ฌด ๊ฒƒ๋„ ์—†๋Š” ์ƒํƒœ์—์„œ 1๋ฒˆ ํ˜ธ์ถœ๋˜๊ณ , API๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ๋ฆฌ๋ Œ๋” ๋˜์–ด 2๋ฒˆ์งธ ํ˜ธ์ถœ์ผ ๋ฐœ์ƒํ•˜๊ธฐ์— 2๋ฒˆ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Œ


### - ๋ฌธ์ œ์ 

- ์ผ๊ธฐ์˜ `๋‚ด์šฉ์„ ์ˆ˜์ •`ํ•˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ์ถœ๋ ฅํ•˜๋Š” `๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๊ฐœ์ˆ˜`, `๊ธฐ๋ถ„ ๋‚˜์œ ์ผ๊ธฐ ๊ฐœ์ˆ˜`, `๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๋น„์œจ`์— ์–ด๋– ํ•œ ์˜ํ–ฅ๋„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.
- ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  `๋‚ด์šฉ์„ ์ˆ˜์ •`ํ•˜๋ฉด `๋ฆฌ๋ Œ๋”`๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  "์ผ๊ธฐ ๋ถ„์„ ์‹œ์ž‘"์ด ์ฝ˜์†”์— ์ถœ๋ ฅ๋˜๋ฉฐ `์ผ๊ธฐ ๋ถ„์„ ํ•จ์ˆ˜๊ฐ€ ๋˜ ํ˜ธ์ถœ`๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
- ํ˜„์žฌ๋Š” ํ•จ์ˆ˜ ํ•˜๋‚˜๊ฐ€ ํ˜ธ์ถœ๋˜์ง€๋งŒ, ์ผ๊ธฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๊ฑฐ๋‚˜, ๋” ๋งŽ์€ ํ•จ์ˆ˜๊ฐ€ ๋ฆฌ๋ Œ๋” ์‹œ, ํ˜ธ์ถœ๋œ๋‹ค๋ฉด ํ”„๋กœ๊ทธ๋žจ์˜ ์‚ฌ์šฉ์„ฑ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.
- ๋”ฐ๋ผ์„œ ๋ฆฌ๋ Œ๋” ๋  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, `ํŠน์ • ๊ฐ’์ด ๋ณ€ํ™”ํ•  ๋•Œ๋งŒ` ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.


### 9-4. useMemo

- ์œ„์˜ ๋ฌธ์ œ๋ฅผ useMemo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
- useMemo๋Š” `์ฝœ๋ฐฑํ•จ์ˆ˜`, `dependency ๋ฐฐ์—ด`์„ ์ธ์ž๋กœ ๋ฐ›์Œ, (useEffect์™€ ์œ ์‚ฌ)

```javascript
// App.js

const getDiaryAnalysis = useMemo(() => {
console.log("์ผ๊ธฐ ๋ถ„์„ ์‹œ์ž‘");

const goodCount = data.filter((it) => it.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100;
return { goodCount, badCount, goodRatio };
}, [data.length]);
```

- ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ  ํ•ด๋‹น ๋ฆฌํ„ด ๊ฐ’์„ ๊ณ„์† ๊ธฐ์–ตํ•ด๋‘”๋‹ค.
- ๊ทธ๋ฆฌ๊ณ  dependency ๋ฐฐ์—ด์— ๋‹ด๊ธด ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฆฌํ„ด ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
- ํ•˜์ง€๋งŒ dependency ๋ฐฐ์—ด์— ๋‹ด๊ธด ๊ฐ’์ด ๋ณ€ํ™”ํ•˜๋ฉด ์ƒˆ๋กœ ์—…๋ฐ์ดํŠธ๋œ ๋ฆฌํ„ด ๊ฐ’์„ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
- ๋”ฐ๋ผ์„œ ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.


### - useMemo์˜ ํƒ€์ž… (์‹ค์ˆ˜ ์ฃผ์˜)

- useMemo๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ดํ•˜๋Š” ๊ฐ’์„ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— getDiaryAnalysis๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ์ƒ์ˆ˜๊ฐ€ ๋จ

```javascript
// App.js

const { goodCount, badCount, goodRatio } = getDiaryAnalysis;
```

- ๋”ฐ๋ผ์„œ `getDiaryAnalysis();`์™€ ๊ฐ™์ด ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ–ˆ์—ˆ์ง€๋งŒ useMemo๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด `getDiaryAnalysis`๋กœ ๊ฐ€์ ธ์™€์•ผ ํ•จ
- ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๊ฐ€์ ธ์˜ฌ ๊ฒฝ์šฐ, ์—๋Ÿฌ ๋ฐœ์ƒ


![useMemo](README_img/useMemo.gif)




## 10. ์ตœ์ ํ™”2 ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ - React.memo

### 10-1. ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”

- count์™€ text๋ผ๋Š” ์ƒํƒœ๋ฅผ ๊ฐ€์ง„ App์—์„œ count ๊ฐ’์ด ๋ณ€ํ™”ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

![๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”](README_img/React_memo_background.png)

- `state๊ฐ€ ๋ณ€ํ™”`ํ•˜๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์™€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์€ `๋ชจ๋‘ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋ฐœ์ƒ`
- ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ์— ์ปดํฌ๋„ŒํŠธ์˜ ์–‘์ด ๋งŽ์„ ๊ฒฝ์šฐ, `์„ฑ๋Šฅ ๋น„ํšจ์œจ`์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


### 10-2. ํ•ด๊ฒฐ๋ฐฉ์•ˆ

- ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— `์กฐ๊ฑด์„ ์ง€์ •`ํ•œ๋‹ค.
- ํ•ด๋‹น ์กฐ๊ฑด์ด `์ถฉ์กฑ`๋  ๊ฒฝ์šฐ์—๋งŒ `๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰`ํ•˜๋„๋ก ํ•จ

![ํ•ด๊ฒฐ๋ฐฉ์•ˆ](README_img/React_memo_solution.png)


### 10-3. React.memo

- ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ `๋™์ผํ•œ props`์„ `๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ`๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์„œ `๋™์ผํ•œ ๋ Œ๋”๋ง`์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ, ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ Œ๋”๋ง๋œ ๊ฒฐ๊ณผ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
- props์— ์˜ํ•ด์„œ๋งŒ ๋ Œ๋”๋ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ, state๋“ฑ์˜ ๋ณ€ํ™” ์‹œ์—๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒํ•จ


### - React.memo ํ…Œ์ŠคํŠธ

- ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์ธ OptimizeTest๋ฅผ ์ƒ์„ฑ
- `count`์™€ `text`์˜ ๋‘ ๊ฐœ์˜ ์ƒํƒœ๋ฅผ ์ƒ์„ฑ
- ์ž์‹ ์ปดํฌ๋„ŒํŠธ์ธ CountView์™€ TextView์— ๊ฐ๊ฐ props ์ „๋‹ฌ

```javascript
// OptimizeTest.js

const OptimizeTest = () => {
const [count, setCount] = useState(1);
const [text, setText] = useState("");

return (



count



setCount(count + 1)}>+


text



{
setText(e.target.value);
}}
/>


);
};
```


```javascript
// Optimize.js

import { useState, useEffect } from "react";

const TextView = ({ text }) => {
useEffect(() => {
console.log(`Update :: text : ${text}`);
});
return

{text}
;
};

const CountView = ({ count }) => {
useEffect(() => {
console.log(`Update :: count : ${count}`);
});
return

{count}
;
};
```

- `CountView`์™€ `TextView` ๋‘ ๊ฐœ์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑ
- ๊ฐ๊ฐ prop์œผ๋กœ count์™€ text๋ฅผ ๋ฐ›๋Š”๋‹ค.
- useEffect๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  dependency ๋ฐฐ์—ด์„ ๋ฐ›์ง€ ์•Š๊ฒŒํ•˜์—ฌ ์–ด๋–ค ์š”์†Œ๋ผ๋„ Update(๋ฆฌ๋ Œ๋”)๋˜๋ฉด ์ฝ˜์†”์„ ์ถœ๋ ฅํ•˜๋„๋ก ์„ค์ •


![React.memo ์ ์šฉ ์ „](README_img/React_memo_non.png)

<์ž์‹ ์ปดํฌ๋„ŒํŠธ ๋™์‹œ์— ๋ฆฌ๋ Œ๋”๋˜์–ด ์ฝ˜์†” ์ถœ๋ ฅ>


```javascript
// Optimize.js

import React, { useState, useEffect } from "react";

const TextView = React.memo(({ text }) => {
useEffect(() => {
console.log(`Update :: text : ${text}`);
});
return

{text}
;
});

const CountView = React.memo(({ count }) => {
useEffect(() => {
console.log(`Update :: count : ${count}`);
});
return

{count}
;
});
```

- React๋ฅผ importํ•˜๊ธฐ
- props๋ฅผ ๋ฐ›๋Š” ์ž์‹์˜ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ์ „์ฒด๋ฅผ `React.memo()`๋กœ ๊ฐ์‹ธ๊ธฐ
- ์ด๋ ‡๊ฒŒ ํ•˜๊ฒŒ ๋˜๋ฉด props์˜ ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”ํ•˜๊ฒŒ ๋œ๋‹ค.


![React.memo ์ ์šฉ ํ›„](README_img/React_memo_using.png)


### - props๋กœ ๊ฐ์ฒด๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ : ๋ฌธ์ œ์ 

```javascript
// OptimizeTest.js

const OptimizeTest = () => {
const [count, setCount] = useState(1);
const [obj, setObj] = useState({
count: 1,
});

return (



Counter A



{
setCount(count);
}}
>
A button



Counter B



{
setObj({ count: obj.count });
}}
>
B button



);
};
```

- state๋กœ count, obj ๋ฐ์ดํ„ฐ ์„ค์ •
- `setCount(count)`, `setObj({ count: obj.count })`๋กœ ๊ธฐ์กด ๋ฐ์ดํ„ฐ์™€ ๊ฐ™์€ ๊ฐ’์„ state๋กœ ์ „๋‹ฌ


```javascript
//OptimizeTest.js

import React, { useState, useEffect } from "react";

const CounterA = React.memo(({ count }) => {
useEffect(() => {
console.log(`CounterA Update - count : ${count}`);
});
return

{count}
;
});

const CounterB = React.memo(({ obj }) => {
useEffect(() => {
console.log(`CounterB Update - count : ${obj.count}`);
});
return

{obj.count}
;
});
```

- useMemo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ OptimizeTest๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ props์ธ count์™€ obj๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด useEffect์— ์˜ํ•ด์„œ ์ฝ˜์†”์— ์—…๋ฐ์ดํŠธ ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋˜๋„๋ก ์„ค์ •ํ•˜์˜€๋‹ค.
- CounterA ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ, `count` ๊ฐ’์ด `setCount(count)`์— ์˜ํ•ด ๋™์ผํ•œ ๊ฐ’์„ ๋ณด๋‚ด๊ธฐ์— `๋ฆฌ๋ Œ๋”๋˜์ง€ ์•Š์Œ`
- ๋ฐ˜๋ฉด CounterB ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ, `obj` ๊ฐ’์ด `setObj({ count: obj.count })`๋กœ ๊ฐ’์˜ ๋ณ€ํ™”๊ฐ€ ์—†์ง€๋งŒ `๋ฆฌ๋ Œ๋”๊ฐ€ ๋ฐœ์ƒ`ํ•œ๋‹ค.


<๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋Š” ๋ฐฉ๋ฒ•>

```javascript
const a = {count: 1};
const b = {count: 1};
```

- ์œ„์˜ ๊ฒฝ์šฐ, `a === b`๋Š” true์ผ๊นŒ?
- ์ •๋‹ต์€ false
- ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒฝ์šฐ, ๊ฐ์ฒด์˜ `์ฃผ์†Œ(ํ•ด์‹œ)`๋ฅผ ๋น„๊ตํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด ์ฃผ์†Œ๊ฐ€ ๋‹ค๋ฅด๊ธฐ์— ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋œ๋‹ค. (`์–•์€ ๋น„๊ต`)
- ๋”ฐ๋ผ์„œ ๋™์ผํ•œ props๋ฅผ ๋ฐ›์€ ๊ฒƒ๊ฐ™์ง€๋งŒ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ํŒ๋‹จํ•˜๊ธฐ์— React.memo์—์„œ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค.


```javascript
const a = {count: 1};
const b = a;
```

- ์ด ๊ฒฝ์šฐ๋Š” b์—์„œ a ์ž์ฒด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๊ฐ™์€ ๊ฐ์ฒด ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ธฐ์— `a === b`๊ฐ€ `true`์ด๋‹ค.


### - props๋กœ ๊ฐ์ฒด๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ : ํ•ด๊ฒฐ - areEqual() ํ•จ์ˆ˜

```javascript
// OptimizeTest.js

const CounterB = ({ obj }) => {
useEffect(() => {
console.log(`CounterB Update - count : ${obj.count}`);
});
return

{obj.count}
;
};
```

- ๊ธฐ์กด CounterB ์ปดํฌ๋„ŒํŠธ์—์„œ React.memo ์ œ๊ฑฐ


```javascript
// OptimizeTest.js

const areEqual = (prevProps, nextProps) => {
if (prevProps.obj.count === nextProps.obj.count) {
return true; // ์ด์ „ props์™€ ํ˜„์žฌ props๊ฐ€ ๊ฐ™๋‹ค -> ๋ฆฌ๋ Œ๋” ๋ฐœ์ƒ ์•ˆ ํ•จ
}
return false; // ์ด์ „ props์™€ ํ˜„์žฌ props๊ฐ€ ๋‹ค๋ฅด๋‹ค -> ๋ฆฌ๋ Œ๋” ๋ฐœ์ƒ
};

// -------------------------------------------------

// ์ถ•์•ฝ๋œ ์ฝ”๋“œ

const areEqual = (prevProps, nextProps) => {
return prevProps.obj.count === nextProps.obj.count;
};
```

- ๋‘ ๊ฐœ์˜ ๊ฐ์ฒด ์ธ์ž๋ฅผ ๋ฐ›์•„ ๊ฐ’์ด ๊ฐ™์€์ง€ ๋น„๊ตํ•˜์—ฌ `๊ฐ™์œผ๋ฉด true`, `๋‹ค๋ฅด๋ฉด false`๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜ `areEqual`์„ ์ƒ์„ฑ


```javascript
// OptimizeTest.js

const MemoizedCounterB = React.memo(CounterB, areEqual);

...


Counter B



{
setObj({ count: obj.count });
}}
>
B button


...
```

- React.memo์— ๊ธฐ์กด์˜ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ `CounterB`์™€ ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” ํ•จ์ˆ˜ `areEqual`์„ ์ธ์ž๋กœ ์ฃผ๋ฉด ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•จ
- ์ด ํ•จ์ˆ˜๋ฅผ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์— ์‚ฌ์šฉํ•˜๋ฉด props๋กœ ๋ฐ›์€ ๊ฐ์ฒด์˜ ์–•์€ ๋น„๊ต๋ฅผ ํ•˜์ง€์•Š๊ณ , ๋‘ ๋ฒˆ์งธ ์ธ์ž์˜ areEqual์ด ๋ฆฌํ„ดํ•˜๋Š” true/false์— ๋”ฐ๋ผ ๋ฆฌ๋ Œ๋”๋ฅผ ๊ฒฐ์ •ํ•˜๊ฒŒ ๋œ๋‹ค.




## 11. ์ตœ์ ํ™”3 ์ปดํฌ๋„ŒํŠธ & ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ - useCallback

### 11-1. ์ตœ์ ํ™”ํ•  ์š”์†Œ ์ฐพ๊ธฐ

### - React Developer Tools ํ™œ์šฉ

- ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ €์˜ ํ™•์žฅ ์•ฑ์œผ๋กœ ๋ฉ”ํƒ€(Meta)์—์„œ ๊ฐœ๋ฐœํ•จ
- ๋ธŒ๋ผ์šฐ์ € ์ƒ์˜ ํŽ˜์ด์ง€๊ฐ€ React ๊ธฐ๋ฐ˜์œผ๋กœ ์ œ์ž‘๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ
- ์˜ต์…˜์—์„œ `Highlight updates when components render`๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ฉด ํ˜„์žฌ `๋ฆฌ๋ Œ๋”`๋ง๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ `ํ•˜์ด๋ผ์ดํŠธ` ํ•ด์คŒ


![๋ฆฌ์•กํŠธ ๊ฐœ๋ฐœ ๋„๊ตฌ ํ•˜์ด๋ผ์ดํŠธ ๊ธฐ๋Šฅ](README_img/React_highlight.gif)

<์ผ๊ธฐ ๋‚ด์šฉ์ด ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค DiaryEditor.js ์˜์—ญ์ด ๋…ธ๋ž€์ƒ‰์œผ๋กœ ํ•˜์ด๋ผ์ดํŠธ๋จ>


### - ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ

- ๋ณธ์ธ์ด ๊ฐ€์ง„ state๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ
- ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š” ๊ฒฝ์šฐ
- ์ž์‹ ์ด ๋ฐ›์€ props๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ


### 11-2. useCallback

- ReactHooks ์ค‘ ํ•˜๋‚˜
- useCallback์€ useMemo์™€ ๋™์ผํ•˜๊ฒŒ ๊ตฌ์„ฑ๋˜๋‚˜ `useMemo`๋Š” ๋™์ผํ•œ `์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ ๊ฐ’`์„ ๋ฆฌํ„ดํ•˜๋Š” ๋ฐ˜๋ฉด, `useCallback`์€ `์ฝœ๋ฐฑํ•จ์ˆ˜`๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
- dependency ๋ฐฐ์—ด์˜ ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ๋™์ผํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋„์›€

```javascript
// useCallback ๊ธฐ๋ณธ๊ตฌ์„ฑ(์ฝœ๋ฐฑํ•จ์ˆ˜, dependency ๋ฐฐ์—ด)

const memoizationCallback = useCallback(
() => {
doSometing(a, b);
}, [a, b]
);
```


### 11-3. useCallback ์‚ฌ์šฉ

- DiaryList์—์„œ ๋ณ€ํ™”๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ, data ๋ณ€์ˆ˜๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๊ณ  data๋ฅผ state๋กœ ๊ฐ€์ง€๋Š” App.js(๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ)๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋œ๋‹ค.
- ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๊ธฐ์— ์ž์‹ ์ปดํฌ๋„ŒํŠธ์ธ `DiaryList`์™€ `DiaryEditor` ๋ชจ๋‘ ๋ฆฌ๋ Œ๋”๋ง ๋œ๋‹ค.
- ํ•˜์ง€๋งŒ data๊ฐ€ ๋ณ€ํ™”ํ•˜๋”๋ผ๋„ `DiaryEditor`๋Š” `๋ฆฌ๋ Œ๋”๋ง ๋  ํ•„์š”๊ฐ€ ์—†๋‹ค`.
- DiaryEditor๋Š” ๋ถ€๋ชจ App ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ `onCreate` ํ•จ์ˆ˜๋ฅผ props๋กœ ๋ฐ›๊ณ  ์žˆ๋‹ค.
- ๋”ฐ๋ผ์„œ ๋™์ผํ•œ onCreate ํ•จ์ˆ˜๋ฅผ props๋กœ ๋ฐ›์•„ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋„๋ก `onCreate` ํ•จ์ˆ˜์— `useCallback`์„ ์‚ฌ์šฉํ•˜๊ณ  `DiaryEditor`๋Š” ๋™์ผํ•œ props๋ฅผ ๋ฐ›์œผ๋ฉด ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋„๋ก `React.memo`๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

```javascript
// DiaryEditor.js

export default React.memo(DiaryEditor);
```

```javascript
// App.js

const onCreate = useCallback((author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData([newItem, ...data]);
}, []);
```


### 11-4. ์ตœ์ ํ™”์˜ ๋”œ๋ ˆ๋งˆ

- useCallback์„ ์ ์šฉํ•œ ํ˜„์žฌ DiaryEditor์—์„œ ์ผ๊ธฐ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด, onCreate๊ฐ€ ์ˆ˜ํ–‰๋˜๋Š”๋ฐ useCallback์˜ `dependency`์— `๋นˆ๋ฐฐ์—ด`์„ ๋‹ด๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ดˆ์˜ mount๋  ๋•Œ์˜ `data(๋นˆ๋ฐฐ์—ด)`๋งŒ ๊ธฐ์–ตํ•˜์—ฌ `์ž‘์„ฑ๋œ ์ผ๊ธฐ๋ฅผ ๋นˆ๋ฐฐ์—ด์— ๊ณ„์† ๋„ฃ๊ฒŒ ๋œ๋‹ค`.
- ๋ฐ‘๋น ์ง„ ๋…์— ๋ฌผ๋ถ“๊ธฐ์™€ ๊ฐ™์€ ํ˜„์ƒ ๋ฐœ์ƒ
- `dependency ๋ฐฐ์—ด`์— `data`๋ฅผ ๋„ฃ๊ฒŒ ๋˜๋ฉด, data๋ฅผ `์ฐธ์กฐ`๋ฐ›์•„ ๊ธฐ์กด ์ผ๊ธฐ์— ์ƒˆ๋กœ ์ž‘์„ฑ๋œ ์ผ๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜์ง€๋งŒ `data๊ฐ€ ๋ณ€ํ™”`ํ•  ๋•Œ๋งˆ๋‹ค `DiaryEditor๊ฐ€ ๋ฆฌ๋ Œ๋”`๋˜์–ด useCallback์„ ์‚ฌ์šฉํ•œ `์ด์ ์ด ์‚ฌ๋ผ์ง„๋‹ค`.


### 11-5. ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ

- setState ํ•จ์ˆ˜์— ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ

```javascript
// App.js

const onCreate = useCallback((author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData((data) => [newItem, ...data]);
}, []);
```

- `setData((data) => [newItem, ...data])`๋ฅผ ๋ณด๋ฉด setData ํ•จ์ˆ˜ ๋‚ด์— ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  data๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ์—…๋ฐ์ดํŠธ๋œ ๋ฐฐ์—ด์„ ๋ฆฌํ„ดํ•œ๋‹ค.
- ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด dependency ๋ฐฐ์—ด์€ data๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์•„ data๊ฐ€ ์ˆ˜์ •๋˜๋”๋ผ๋„ onCreate๋Š” ๋™์ผํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•˜์—ฌ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ
- ๋Œ€์‹  setData์—์„œ ์ฝœ๋ฐฑํ•จ์ˆ˜ `์ธ์ž`๋กœ `data`๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ์— data๊ฐ€ `๋นˆ๋ฐฐ์—ด๋กœ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š๋Š”๋‹ค`.




## 12. ์ตœ์ ํ™”4 - React.memo + useCallback

### 12-1. ์ตœ์ ํ™” ํ•„์š” ๋ถ€๋ถ„

- DiaryItem์—์„œ `์ผ๊ธฐ ํ•˜๋‚˜`๊ฐ€ ์‚ญ์ œ๋  ๊ฒฝ์šฐ, `๋ชจ๋“  ์ผ๊ธฐ๋“ค์ด ๋ฆฌ๋ Œ๋”๋ง`๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Œ
- ์ผ๊ธฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์ด ์žˆ์„ ๊ฒฝ์šฐ, ์„ฑ๋Šฅ์— ์ข‹์ง€ ์•Š์Œ


### 12-2. React.memo์™€ useCallback ์ ์šฉ

```javascript
// DiaryItem.js

const DiaryItem = ({onEdit, onRemove, author, content, created_date, emotion, id}) => {
...
}

export default React.memo(DiaryItem);
```

- `React.memo`๋กœ `๋™์ผํ•œ props`๋ฅผ ๋ฐ›์„ ๊ฒฝ์šฐ, `๋ฆฌ๋ Œ๋” ๋ฐœ์ƒ ๋ฐฉ์ง€`
- ํ˜„์žฌ DiaryItem ์ปดํฌ๋„ŒํŠธ๋Š” onEdit, onRemove, author, content, created_date, emotion, id๋ฅผ props๋กœ ๋ฐ›๊ณ  ์žˆ์Œ
- author, content, created_date, emotion, id๋Š” ๋™์ผํ•œ ๊ฐ’์˜ props๋ฅผ ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์„ React.memo๋ฅผ ํ†ตํ•ด ์ธ์‹ํ•  ์ˆ˜ ์žˆ์Œ
- ํ•˜์ง€๋งŒ, onEdit, onRemove์˜ ๊ฒฝ์šฐ, ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์–•์€ ๋น„๊ต๋กœ ๋™์ผํ•œ ํ•จ์ˆ˜์ธ์ง€ ์•„๋‹Œ์ง€ React.memo์—์„œ๋Š” ํŒ๋ณ„์ด ์–ด๋ ค์›€
- ๋”ฐ๋ผ์„œ `onEdit`๊ณผ `onRemove`์— `useCallback`์œผ๋กœ ๋™์ผํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋ณด๋‚ด๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•จ


```javascript
// App.js

const onRemove = useCallback((targetId) => {
setData((data) => data.filter((it) => it.id !== targetId));
}, []);

const onEdit = useCallback((targetId, newContent) => {
setData((data) =>
data.map((it) =>
it.id === targetId ? { ...it, content: newContent } : it,
),
);
}, []);
```

- App ์ปดํฌ๋„ŒํŠธ์—์„œ onRemove ํ•จ์ˆ˜์™€ onEdit ํ•จ์ˆ˜์— useCallback ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  dependency ๋ฐฐ์—ด์€ ๋นˆ๋ฐฐ์—ด๋กœ ์ฒ˜๋ฆฌ
- useCallback์˜ ๋”œ๋ ˆ๋งˆ์— ๋น ์ง€์ง€ ์•Š๊ณ  setState์—์„œ ์ตœ์‹ ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด data๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰
- ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด DiaryItem ํ•˜๋‚˜๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ๋„ ๋‹ค๋ฅธ DiaryItem๋“ค์ด ๋ฆฌ๋ Œ๋” ๋˜์ง€ ์•Š์Œ


![React.memo + useCallback](README_img/React_memo_useCallback.gif)




## 13. ๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง ๋ถ„๋ฆฌํ•˜๊ธฐ - useReducer

### 13-1. App ์ปดํฌ๋„ŒํŠธ์˜ ๋ณต์žกํ•จ

![App์˜ ์ƒํƒœ๋ณ€ํ™”ํ•จ์ˆ˜](README_img/React_setStates.png)

- ํ˜„์žฌ App ์ปดํฌ๋„ŒํŠธ์—๋Š” useState๋กœ ์ธํ•˜์—ฌ `setState`์ธ ์ƒํƒœ ๋ณ€ํ™” ์ฒ˜๋ฆฌํ•จ์ˆ˜๊ฐ€ `์ฝ”๋“œ ์ƒ์— ๋งŽ์ด ํฌํ•จ`๋˜์–ด์žˆ์Œ
- ์ด ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜๋“ค์€ ๋ชจ๋‘ `data๋ฅผ ์‚ฌ์šฉ`ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— App ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž‘์„ฑ๋˜์—ˆ์Œ
- App ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•˜๊ณ  ๊ธธ์–ด์ง
- ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋” ๋ณต์žกํ•ด์ง


### 13-2. useReducer

- React Hooks ์ค‘ ํ•˜๋‚˜
- ์ปดํฌ๋„ŒํŠธ์—์„œ `์ƒํƒœ ๋ณ€ํ™” ๋กœ์ง`์„ `๋ถ„๋ฆฌ`ํ•˜์—ฌ ๋”ฐ๋กœ ๊ด€๋ฆฌ


```jsx
const Counter = () => {
const [count, setCount] = useState(0);

const add1 = () => {
setCount(count + 1);
};

const add10 = () => {
setCount(count + 10);
};

const add100 = () => {
setCount(count + 100);
};

return (


{count}
add 1
add 10
add 100

)
};
```


```jsx
// ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง ๋ถ„๋ฆฌ

const reducer = (state, action) => {
switch (action.type) {
case 1:
return state + 1;
case 10:
return state + 10;
case 100:
return state + 100;
default:
return state;
}
}
```

- ์ƒํƒœ ๋ณ€ํ™” ๋กœ์ง์„ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ `switch-case ๋ฌธ๋ฒ•`์ฒ˜๋Ÿผ ํ™œ์šฉ
- `state` : ํ˜„์žฌ ๊ฐ€์žฅ ์ตœ์‹ ์˜ state
- `action` : dispatch ํ˜ธ์ถœ ์‹œ ์ „๋‹ฌํ•œ ์ธ์ž์ธ `action ๊ฐ์ฒด`


```jsx
// useReducer ์ ์šฉ

const Counter = () => {
const [count, dispatch] = useReducer(reducer, 1);

return (


{count}
dispatch({ type: 1})}>add 1
dispatch({ type: 10})}>add 10
dispatch({ type: 100})}>add 100

)
};
```

- useState์™€ ๊ฐ™์ด `๋น„๊ตฌ์กฐํ™” ํ• ๋‹น` ์‚ฌ์šฉ
- `count` : 0๋ฒˆ ์ธ๋ฑ์Šค๋กœ ์ƒํƒœ(state)
- `dispatch` : 1๋ฒˆ ์ธ๋ฑ์Šค๋กœ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ผ์œผํ‚ค๋Š”(`raise`) ํ•จ์ˆ˜
- `useReducer()` : ์ƒํƒœ ๋ณ€ํ™” ๊ด€๋ฆฌ React Hook
- `reducer` : 0๋ฒˆ ์ธ๋ฑ์Šค๋กœ dispatch์—์„œ ์ผ์–ด๋‚œ `์ƒํƒœ๋ณ€ํ™” action์„ ์ฒ˜๋ฆฌ`ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜
- `1` : ์ƒํƒœ์ธ count์˜ `์ดˆ๊ธฐ ๊ฐ’`
- `dispatch({ type: 1 })` : dispatch ํ˜ธ์ถœ ์‹œ, ์ „๋‹ฌํ•˜๋Š” {type: 1}๊ณผ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ `action ๊ฐ์ฒด`๋ผ๊ณ  ํ•จ


### 13-3. App ์ปดํฌ๋„ŒํŠธ์— useReducer ์ ์šฉํ•˜๊ธฐ

```jsx
// App.js

// reducer ํ•จ์ˆ˜ ๋”ฐ๋กœ ์ƒ์„ฑ

const reducer = (state, action) => {
switch (action.type) {
// ์ฒ˜์Œ Mount ๋  ๋•Œ,
case "INIT": {
return action.data; // action์— ๋‹ด๊ธด data ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ด
}
// ์ƒ์„ฑํ•  ๋•Œ,
case "CREATE": {
const created_date = new Date().getTime(); // ์ƒ์„ฑ์ผ์ž ๋”ฐ๋กœ ์ฒ˜๋ฆฌ
const newItem = {
...action.data,
created_date,
}; // ๋ฐ›์€ action์˜ data์— ์ƒ์„ฑ์ผ์ž ์ถ”๊ฐ€ํ•œ ์ƒˆ๋กœ์šด ์ผ๊ธฐ newItem
return [newItem, ...state]; // ๊ธฐ์กด ์ผ๊ธฐ state์— newItem ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฆฌํ„ด
}
// ์‚ญ์ œํ•  ๋•Œ,
case "REMOVE": {
// ํ•ด๋‹น id๊ฐ€ ์•„๋‹Œ ์ผ๊ธฐ๋งŒ ๋ชจ์•„์„œ ๋ฆฌํ„ด
return state.filter((it) => it.id !== action.targetId);
}
// ์ˆ˜์ •ํ•  ๋•Œ,
case "EDIT": {
// ํ•ด๋‹น id์ธ ์ผ๊ธฐ๋ฅผ ์ฐพ์•„์„œ content๋งŒ action์œผ๋กœ ๋ฐ›์€ newContent๋กœ ์ˆ˜์ •ํ•˜์—ฌ ๋ฆฌํ„ด
return state.map((it) =>
it.id === action.targetId ? { ...it, content: action.newContent } : it,
);
}
default:
return state;
}
};
```

```jsx
// App.js

// useState ๋Œ€์‹  useReducer ์‚ฌ์šฉ
const [data, dispatch] = useReducer(reducer, []);

// ๊ธฐ์กด์˜ setData๋ฅผ ์ด์šฉํ•˜๋Š” ๋ชจ๋“  ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜ ์ˆ˜์ • -> dispatch ์ ์šฉ
const getData = async () => {
const res = await fetch(
"https://jsonplaceholder.typicode.com/comments",
).then((res) => res.json());
const initData = res.slice(0, 20).map((it) => {
return {
author: it.email,
content: it.body,
emotion: Math.floor(Math.random() * 5) + 1,
created_date: new Date().getTime(),
id: dataId.current++,
};
});

dispatch({ type: "INIT", data: initData });
};

const onCreate = useCallback((author, content, emotion) => {
dispatch({
type: "CREATE",
data: { author, content, emotion, id: dataId.current },
});
dataId.current += 1;
}, []);

const onRemove = useCallback((targetId) => {
dispatch({ type: "REMOVE", targetId });
}, []);

const onEdit = useCallback((targetId, newContent) => {
dispatch({ type: "EDIT", targetId, newContent });
}, []);
```

- `dispatch`๋Š” ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋– ํ•œ ์ฒ˜๋ฆฌ์—†์ด ๋ฐ›๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ์— ๊ธฐ์กด์˜ useCallback ๋”œ๋ ˆ๋งˆ์—์„œ ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ ์ฒ˜๋ฆฌ์™€ ๊ฐ™์€ `๋ณ„๋„์˜ ์กฐ์น˜๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๊ดœ์ฐฎ์Œ`




## 14. ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์— ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰ํ•˜๊ธฐ - Context

### 14-1. ์ „๋‹ฌ๋˜๋Š” props์™€ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ™œ์šฉ๋˜๋Š” props

![props ๊ตฌ๋ถ„](README_img/React_Context.png)

- App ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์„ฑ๋œ `onEdit` ํ•จ์ˆ˜์™€ `onRemove` ํ•จ์ˆ˜๋Š” `DiaryList` ์ปดํฌ๋„ŒํŠธ์—๋Š” `์ „๋‹ฌ`๋งŒ ์ด๋ฃจ์–ด์ง€๊ณ  `DiaryItem` ์ปดํฌ๋„ŒํŠธ์—์„œ ์‹ค์งˆ์ ์œผ๋กœ `์‚ฌ์šฉ`๋จ (๋น„ํšจ์œจ์ )
- ์ „๋‹ฌ๋˜๋Š” props๊ฐ€ ๋งŽ์•„์ง€๊ฒŒ ๋˜๋ฉด ์ค‘๊ฐ„์— ์ด๋ฆ„์„ ์ˆ˜์ •ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ํ•  ๋•Œ, ๋ชจ๋‘ ์ˆ˜์ •ํ•ด์ฃผ๋Š” ๋ฐ˜๋ณต ์ž‘์—…์„ ํ•ด์•ผํ•จ
- ์ด๋ฅผ `Props ๋“œ๋ฆด๋ง`์ด๋ผ๊ณ  ํ•จ


### 14-2. Provider, Context

![Provider](README_img/React_Provider.png)

- `Provider ์ปดํฌ๋„ŒํŠธ`์—๊ฒŒ App ์ปดํฌ๋„ŒํŠธ์˜ `๋ชจ๋“  ๋ฐ์ดํ„ฐ`๋ฅผ ์ „๋‹ฌ๋ฐ›์Œ
- ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ Provider๋กœ๋ถ€ํ„ฐ ํ•„์š”ํ•œ props๋ฅผ `์ง์ ‘ ์ „๋‹ฌ` ๋ฐ›์Œ
- ์ด์ฒ˜๋Ÿผ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ Provider์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋˜์–ด props๋ฅผ ์ง์ ‘ ์ „๋‹ฌ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์˜์—ญ์„ `Context`, ๋ฌธ๋งฅ์ด๋ผ๊ณ  ํ•จ
- ๊ฐ™์€ Context์— ์†ํ•ด์žˆ์ง€ ์•Š์œผ๋ฉด prop์„ provider๋กœ๋ถ€ํ„ฐ ์ง์ ‘ ์ „๋‹ฌ ๋ฐ›๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅ


### - Context ์ƒ์„ฑ

```jsx
const MyContext = React.createContext(defaultValue);
```

- Context๋ฅผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•˜๋„๋ก React์˜ `Context API`๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Œ
- `createContext` : Context ์ƒ์„ฑ ํ•จ์ˆ˜


### - Context Provider๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰

```jsx

{/*์ด context์•ˆ์— ์œ„์น˜ํ•  ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค*/}

```

- `Childern Props` : ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ props๋กœ ์ „๋‹ฌ
- ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์ˆ˜์˜ ์ œํ•œ์€ ์—†์Œ


### 14-3. ์ฝ”๋“œ์— ์ ์šฉ

### - data๋ฅผ ๊ด€๋ฆฌํ•  Context ์ƒ์„ฑ

```jsx
// App.js

export const DiaryStateContext = React.createContext();
```

- ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ importํ•  ์ˆ˜ ์žˆ๋„๋ก `export` ํ•ด์ฃผ์–ด์•ผ ํ•จ


### - data Context์˜ Provider ์ปดํฌ๋„ŒํŠธ๋กœ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ๊ฐ์‹ธ๊ธฐ

```jsx
// App.js



์ „์ฒด ์ผ๊ธฐ : {data.length}

๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๊ฐœ์ˆ˜ : {goodCount}

๊ธฐ๋ถ„ ๋‚˜์œ ์ผ๊ธฐ ๊ฐœ์ˆ˜ : {badCount}

๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๋น„์œจ : {goodRatio}


```

- DiaryStateContext์˜ Provider ์ปดํฌ๋„ŒํŠธ์— value๋ฅผ data๋กœ ์ง€์ •


### - DiaryList ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•ด๋‹น props ๋ฐ›๊ธฐ

```jsx
// DiaryList.js

const DiaryList = () => {
const diaryList = useContext(DiaryStateContext);
};
```

- ๊ธฐ์กด์˜ props๋Š” ์ œ๊ฑฐํ•˜๊ณ  React Hooks์˜ ํ•˜๋‚˜์ธ `useContext`๋ฅผ ํ†ตํ•ด Context์—์„œ diaryList ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด


### - ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜๋„ ๊ด€๋ฆฌํ•  Context ์ƒ์„ฑ

```jsx
export const DiaryDispatchContext = React.createContext();
```

- `data`์™€ `์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜`๋ฅผ `ํ•˜๋‚˜์˜ Context`์—์„œ ๊ด€๋ฆฌํ•  ๊ฒฝ์šฐ, ๊ธฐ์กด์˜ React.memo์™€ useCallback์œผ๋กœ ๋ฆฌ๋ Œ๋”๋ฅผ ๋ฐฉ์ง€ํ•œ `์ตœ์ ํ™”๊ฐ€ ํ’€๋ ค๋ฒ„๋ฆฌ๊ณ ` data๊ฐ€ ์—…๋ฐ์ดํŠธ ๋ ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ `๋ฆฌ๋ Œ๋”๊ฐ€ ๋ฐœ์ƒํ•จ`
- ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ Context์—์„œ ๊ด€๋ฆฌํ•ด์•ผํ•จ


### - ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜๋“ค ํ•˜๋‚˜์˜ ๋ณ€์ˆ˜์— ๋‹ด๊ธฐ

```jsx
// App.js

const memoizedDispatches = useMemo(() => {
return { onCreate, onRemove, onEdit };
}, []);

// ----------------------------------------------

// ์ด๋ ‡๊ฒŒ ๋ฌถ์œผ๋ฉด ์•ˆ ๋จ
const memoizedDispatches = { onCreate, onRemove, onEdit };
```

- ๋‹จ์ˆœ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด์„œ Context์˜ value๋กœ ์ „๋‹ฌํ•˜๋ฉด App ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ, ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜๋“ค๋„ ์žฌ์ƒ์„ฑ๋จ
- ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜์˜ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ ๊ฐ’์„ ๊ธฐ์–ตํ•˜๋Š” useMemo๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•จ


### - ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜ Provider ์ปดํฌ๋„ŒํŠธ ์ ์šฉ

```jsx
// App.js




์ „์ฒด ์ผ๊ธฐ : {data.length}

๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๊ฐœ์ˆ˜ : {goodCount}

๊ธฐ๋ถ„ ๋‚˜์œ ์ผ๊ธฐ ๊ฐœ์ˆ˜ : {badCount}

๊ธฐ๋ถ„ ์ข‹์€ ์ผ๊ธฐ ๋น„์œจ : {goodRatio}



```

- ํ•ด๋‹น Context์˜ Provider ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ค‘์ฒฉํ•˜์—ฌ props๋ฅผ ์ „๋‹ฌ
- value๋กœ ์•ž์„œ ์ƒ์„ฑํ•œ `memoizedDispatches`๋ฅผ ์ง€์ •
- `onCreate={onCreate}`์™€ ๊ฐ™์€ ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜ props๋“ค ์ œ๊ฑฐ


### - Provider์—์„œ props ๋ฐ›๊ธฐ

```jsx
// DiaryEditor.js
const DiaryEditor = () => {
const { onCreate } = useContext(DiaryDispatchContext);
};

```

- ๊ธฐ์กด props ์‚ญ์ œ
- useContext๋กœ DiaryDispatchContext์—์„œ onCreate ๊ฐ€์ ธ์˜ค๊ธฐ


```jsx
// DiaryItem.js

const DiaryItem = ({ id, author, content, emotion, created_date }) => {
const {onEdit, onRemove} = useContext(DiaryDispatchContext);
}
```

- ๊ธฐ์กด props์—์„œ ์ƒํƒœ ๋ณ€ํ™” ํ•จ์ˆ˜ props ์‚ญ์ œ
- useContext๋กœ DiaryDispatchesContext์—์„œ onEdit, onRemove ๊ฐ€์ ธ์˜ค๊ธฐ