Skip to content

Commit

Permalink
docs: React State Management โ€” using Zustand
Browse files Browse the repository at this point in the history
  • Loading branch information
soi-ha committed Aug 19, 2024
1 parent ca27ca4 commit 4f056bc
Showing 1 changed file with 385 additions and 0 deletions.
385 changes: 385 additions & 0 deletions Aug/article/React-State-Management-using-Zustand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,385 @@
## ๐Ÿ”— [React State Management โ€” using Zustand](https://medium.com/globant/react-state-management-b0c81e0cbbf3)

### ๐Ÿ—“๏ธ ๋ฒˆ์—ญ ๋‚ ์งœ: 2024.08.19

### ๐Ÿงš ๋ฒˆ์—ญํ•œ ํฌ๋ฃจ: ์†Œํ•˜(์ตœ์†Œ์—ฐ)

---

<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*y_e4OOiSszPMpyjUD9_BOw.png"/>

๋‹น์‹ ์€ ์ƒํƒœ(state)์™€ ์ƒํƒœ ๊ด€๋ฆฌ(state management)๊ฐ€ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์–ด๋ ค์›Œํ•ด๋ณธ ์ ์ด ์žˆ๊ฑฐ๋‚˜ ๊ฐ„๋‹จํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ๊ณ  ์žˆ์—ˆ๋‹ค๋ฉด, ์ด ๊ธ€์ด ๋‹น์‹ ์„ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ๊ฐ„๋‹จํ•œ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ Zustand๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ค„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ •๋ง๋กœ! ์ƒํƒœ์™€ ์ƒํƒœ ๊ด€๋ฆฌ๋Š” ํ•ญ์ƒ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ค‘์š”ํ•œ ์ธก๋ฉด์ด์—ˆ์Šต๋‹ˆ๋‹ค. React๋Š” ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ๋Š” ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋‚˜ ์ •๋ณด๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์„ฑ์žฅํ•จ์— ๋”ฐ๋ผ ์ƒํƒœ์™€ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค.

### React ์ƒํƒœ ๊ด€๋ฆฌ

React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

1. **React ๋„ค์ดํ‹ฐ๋ธŒ ์ƒํƒœ ๊ด€๋ฆฌ.** useState, useReducer, useRef, useContext์™€ ๊ฐ™์€ ํ›…(hooks)๊ณผ ์‚ฌ์šฉ์ž ์ •์˜ ํ›…(custom hooks)์€ ๋„ค์ดํ‹ฐ๋ธŒ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
2. **๊ฐ„์ ‘ ์ƒํƒœ ๊ด€๋ฆฌ์ž.** React Router์™€ React Query์™€ ๊ฐ™์€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์€ ์ฃผ๋กœ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜์ง€ ์•Š์ง€๋งŒ, ๋„ค์ดํ‹ฐ๋ธŒ ํ›…๊ณผ ๊ฒฐํ•ฉํ•˜๋ฉด ์ƒํƒœ๋ฅผ ์ž˜ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
3. **์ง์ ‘ ์ƒํƒœ ๊ด€๋ฆฌ์ž.** ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Redux, Zustand, Jotai, Valtio๊ฐ€ ์ด ๋ฒ”์ฃผ์— ์†ํ•ฉ๋‹ˆ๋‹ค.

### Zustand๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

Zustand๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ž‘๊ณ  ๋น ๋ฅด๋ฉฐ ํ™•์žฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ„๋‹จํ•œ ์‹œ์Šคํ…œ์œผ๋กœ, ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. Redux ๋ฐ ์œ ์‚ฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ณด๋‹ค ์ ์€ ์ฝ”๋“œ๋กœ React ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Zustand๋Š” provider์— ์˜์กดํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, React ๋กœ์ง์„ ๋œ ์ž‘์„ฑํ•ด๋„ ๋˜๋ฉฐ, ์šฐ๋ฆฌ๊ฐ€ ์ข…์ข… ์žŠ๊ธฐ ์‰ฌ์šด ๋ถ€๋ถ„๋“ค์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ„์†Œํ™”๋œ flux ์›์น™์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘๋™ํ•˜๋ฉฐ, ์ฃผ๋กœ Hook์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์™œ Zustand๋ฅผ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ์š”?

- Zustand๋Š” context๋ณด๋‹ค ๋น ๋ฆ…๋‹ˆ๋‹ค. ํŠน์ • ์ƒํƒœ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
- ์ƒํƒœ ๋ณ‘ํ•ฉ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด ์ƒํƒœ `{x:1, y:2}`์˜ ๋‹จ์ผ ์†์„ฑ์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. `{y:3}`์œผ๋กœ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Zustand๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋ณ‘ํ•ฉํ•ด ์ค๋‹ˆ๋‹ค. ๊ธฐ์กด ์ƒํƒœ๋ฅผ ๋ถ„๋ฐฐํ•˜๊ณ  `{โ€ฆstate, y:3}`์ฒ˜๋Ÿผ ์†์„ฑ์„ ์—…๋ฐ์ดํŠธํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
- Zustand๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™•์žฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์–‘ํ•œ ๋ฏธ๋“ค์›จ์–ด ์œ ํ˜•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- Zustand๋Š” ํŠน์ • ๋ฐฉ์‹์— ์–ฝ๋งค์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ถŒ์žฅ๋˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์ด ์žˆ๋”๋ผ๋„, ๊ทธ๊ฒƒ์„ ๋ฐ˜๋“œ์‹œ ์ฑ„ํƒํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

### Zustand vs. Redux

์•„์‹œ๋‹ค์‹œํ”ผ, Redux๋Š” React์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ๊ณ ์ „์ ์ธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ด๋Š” React ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด ์ด ๊ธ€์˜ ์ ํ•ฉํ•œ ์š”์†Œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ดํŽด๋ณด๋ฉด์„œ Redux๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์„ธ์š”.

<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*GUUEnrvJJTkKSx-XXdvW_w.png"/>

๋จผ์ €, ์•ž์„œ ์„ค๋ช…๋œ ์•„ํ‚คํ…์ฒ˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ํ”„๋ก ํŠธ์—”๋“œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. action creators๋Š” ๊ฐ ์‚ฌ์šฉ์ž ์š”์ฒญ์— ๋Œ€ํ•ด ์˜ฌ๋ฐ”๋ฅธ ์•ก์…˜์ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์•ก์…˜์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ด๋ฒคํŠธ๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฒ„ํŠผ ํด๋ฆญ์ด๋‚˜ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ ๊ฐ™์€ ๊ฒƒ์ด ์ด์— ํ•ด๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. dispatchers๋Š” ์ด๋Ÿฌํ•œ ์•ก์…˜์„ store๋กœ ๋ณด๋‚ด๋Š” ๋ฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค. ์ดํ›„ reducers๋Š” ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. reducer ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ์ƒํƒœ์™€ ์•ก์…˜ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ํ•„์š”์— ๋”ฐ๋ผ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์—…๋ฐ์ดํŠธ๋œ ์ƒํƒœ ์ˆ˜์ • ์‚ฌํ•ญ์ด UI๋ฅผ ๋ Œ๋”๋งํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด์ œ ํฅ๋ฏธ๋กœ์šด ๋ถ€๋ถ„์ด ๋‹ค๊ฐ€์˜ต๋‹ˆ๋‹ค! ์•„๋ž˜์— ์ œ๊ณต๋œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ†ตํ•ด Zustand๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์„ธ์š”. ์ด ๋‹จ์ˆœํ™”๋œ ๋‹ค์ด์–ด๊ทธ๋žจ์— ํฅ๋ฏธ๋ฅผ ๋Š๋‚„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*K5SdovTtjwHe545H6Q2D_A.png"/>

์—ฌ๊ธฐ์—์„œ๋„ UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ๊ทธ๊ฒƒ์€ store๋กœ ๋ผ์šฐํŒ…๋ฉ๋‹ˆ๋‹ค. store๋Š” ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. store๊ฐ€ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด, UI๋Š” ์—…๋ฐ์ดํŠธ๋œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ๊ณผ ํ•จ๊ป˜ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ๋Š” action creator, dispatcher, reducer๊ฐ€ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ , Zustand๋Š” ์ƒํƒœ ๋ณ€๊ฒฝ์„ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด UI๊ฐ€ ๋ฐ์ดํ„ฐ์™€ ๋™๊ธฐํ™” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

> ๋” ํฌ๊ณ  ๋ณต์žกํ•œ ํˆดํ‚ท์ธ Redux์˜ ๋ณต์žก์„ฑ์„ ํ”ผํ•˜๋ฉด์„œ๋„ ๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ€๋ฒผ์šด ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ์ฐพ๊ณ  ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ Zustand๋Š” ์™„๋ฒฝํ•œ ์„ ํƒ์ž…๋‹ˆ๋‹ค.
์ด๋ก ์€ ์—ฌ๊ธฐ์„œ ๋์ž…๋‹ˆ๋‹ค. ์ด์ œ ์‹ค์Šต์„ ์‹œ์ž‘ํ•ด๋ณด์„ธ์š”!

### ReactJs์—์„œ Zustand ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

Zustand๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด React ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ด…์‹œ๋‹ค. ๋„์„œ ๋ฐœํ–‰ ๋ฐ ๋ฐ˜๋‚ฉ์„ ์ถ”์ ํ•˜๋Š” Library Store ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์˜ˆ๋กœ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹จ๊ณ„๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

#### 1. React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ

์•„๋ž˜ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

```bash
npx create-react-app project_name
```

#### 2. Zustand ์˜์กด์„ฑ ์„ค์น˜

ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ํ•˜์—ฌ React ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด Zustand ์˜์กด์„ฑ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

```bash
npm i zustand
```

#### 3. store ์ƒ์„ฑ

bookStore.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋„์„œ store๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

```javascript
import { create } from 'zustand';

const bookStore = (set, get) => ({
books: [],
noOfAvailable: 0,
noOfIssued: 0,
addBook: (book) => {
set((state) => ({
books: [...state.books, { ...book, status: 'available' }],
noOfAvailable: state.noOfAvailable + 1,
}));
},
issueBook: (id) => {
const books = get().books;
const updatedBooks = books?.map((book) => {
if (book.id === id) {
return {
...book,
status: 'issued',
};
} else {
return book;
}
});
set((state) => ({
books: updatedBooks,
noOfAvailable: state.noOfAvailable - 1,
noOfIssued: state.noOfIssued + 1,
}));
},
returnBook: (id) => {
const books = get().books;
const updatedBooks = books?.map((book) => {
if (book.id === id) {
return {
...book,
status: 'available',
};
} else {
return book;
}
});
set((state) => ({
books: updatedBooks,
noOfAvailable: state.noOfAvailable + 1,
noOfIssued: state.noOfIssued - 1,
}));
},
reset: () => {
set({
books: [],
noOfAvailable: 0,
noOfIssued: 0,
});
},
});

const useBookStore = create(bookStore);

export default useBookStore;
```
Zustand store๋Š” hook์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ `useBookStore`๊ฐ€ ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. `create`๋Š” store๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. store๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ณต์œ ํ•˜๋Š” ์œ ์ผํ•œ ์ง„๋ฆฌ์˜ ์›์ฒœ์ž…๋‹ˆ๋‹ค. `set` ํ•จ์ˆ˜๋Š” ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ณ , `get` ํ•จ์ˆ˜๋Š” ์•ก์…˜ ๋‚ด์—์„œ ์ƒํƒœ๋ฅผ ์ ‘๊ทผํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
์ด ์˜ˆ์ œ์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ store์˜ ์ƒํƒœ ๊ฐ์ฒด๋Š” ์„ธ ๊ฐœ์˜ ํ•„๋“œ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. `books`๋Š” ์ฑ…์˜ ID, ์ด๋ฆ„, ์ €์ž์™€ ๊ฐ™์€ ์„ธ๋ถ€ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๋ฐฐ์—ด์„ ํฌํ•จํ•˜๋ฉฐ, `noOfAvailable`์—๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‚ด์˜ ์ด ๋„์„œ ์ˆ˜๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. `noOfIssued`๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐœํ–‰๋œ ๋„์„œ์˜ ์ด ์ˆ˜๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ store๋Š” ๋„ค ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. `addBook` ํ•จ์ˆ˜๋Š” ์ฑ…์˜ ๋ฐฐ์—ด์— ์ƒˆ๋กœ์šด ์ฑ…์„ ์ถ”๊ฐ€ํ•˜๊ณ , ํ˜„์žฌ ์ด์šฉ ๊ฐ€๋Šฅํ•œ ์ฑ…์˜ ์ˆ˜๋ฅผ ๋Š˜๋ฆฌ๋ฉฐ, ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๋ชจ๋“  ์ฑ…์˜ ์ƒํƒœ๋ฅผ "available"๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. `issueBook` ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋„์„œ๋ฅผ ๋ฐœํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋ฉฐ, ๊ด€๋ จ๋œ ๋„์„œ๋Š” "issued" ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ๋ฐœํ–‰ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ์ด์šฉ ๊ฐ€๋Šฅํ•œ ์ฑ…์˜ ์ˆ˜๊ฐ€ ๊ฐ์†Œํ•ฉ๋‹ˆ๋‹ค. `returnBook` ํ•จ์ˆ˜๋Š” ๋ฐœํ–‰๋œ ๋„์„œ๋ฅผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ฐ˜ํ™˜๋œ ๋„์„œ์˜ ์ƒํƒœ๊ฐ€ "available"๋กœ ๋ณ€๊ฒฝ๋˜๊ณ  ๋ฐœํ–‰๋œ ๋„์„œ ์ˆ˜๊ฐ€ ๊ฐ์†Œํ•˜๋ฉฐ ์ด์šฉ ๊ฐ€๋Šฅํ•œ ๋„์„œ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ, `reset` ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋“  ์ƒํƒœ ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
#### 4. ์ปดํฌ๋„ŒํŠธ๋ฅผ store์™€ ์—ฐ๊ฒฐ
๋จผ์ € `App.js` ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด ๋ด…์‹œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.
```javascript
//App.js

import { useEffect } from 'react';
import BookForm from './components/BookForm';
import BookList from './components/BookList';
import useBookStore from './bookStore';
import './App.css';

function App() {
const reset = useBookStore((state) => state.reset);

useEffect(() => {
reset();
}, [reset]);

return (
<div className="App">
<h2>My Library Store</h2>
<BookForm />
<BookList />
</div>
);
}

export default App;
```
`App.js` ํŒŒ์ผ์—๋Š” `BookForm`๊ณผ `BookList`๋ผ๋Š” ๋‘ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. `App` ์ปดํฌ๋„ŒํŠธ๊ฐ€ mount๋  ๋•Œ๋งˆ๋‹ค ์ƒํƒœ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด `reset` ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
์ด์ œ `BookForm.js` ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.
```javascript
//BookForm.js

import { useState } from 'react';
import useBookStore from '../bookStore';

function BookForm() {
const addBook = useBookStore((state) => state.addBook);
const [bookDetails, setBookDetails] = useState({});

const handleOnChange = (event) => {
const { name, value } = event.target;
setBookDetails({ ...bookDetails, [name]: value });
};

const handleAddBook = () => {
if (!Object.keys(bookDetails).length) return alert('Please enter book details!');
addBook(bookDetails);
};

return (
<div className="input-div">
<div className="input-grp">
<label>Book ID</label>
<input type="text" name="id" size={50} onChange={handleOnChange} />
</div>
<div className="input-grp">
<label>Book Name</label>
<input type="text" name="name" size={50} onChange={handleOnChange} />
</div>
<div className="input-grp">
<label>Author</label>
<input type="text" name="author" size={50} onChange={handleOnChange} />
</div>
<button onClick={handleAddBook} className="add-btn">
Add
</button>
</div>
);
}

export default BookForm;
```
`BookForm` ์ปดํฌ๋„ŒํŠธ๋Š” ID, ์ด๋ฆ„, ์ €์ž์™€ ๊ฐ™์€ ์ฑ…์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ํผ ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ด ์ฑ…์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ๋„์„œ store์˜ `addBook` ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” "Add" ๋ฒ„ํŠผ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒ˜ํ”Œ ์ฑ… ์„ธ๋ถ€ ์ •๋ณด์™€ ํ•จ๊ป˜ UI๊ฐ€ ์•„๋ž˜์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*q0b70FPKH7oc3BLGk5CMMw.png"/>
๋‹ค์Œ ์ฝ”๋“œ๋กœ BookList.js ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
```javascript
//BookList.js

import { Fragment } from 'react';
import useBookStore from '../bookStore';

function BookList() {
const { books, noOfAvailable, noOfIssued, issueBook, returnBook } = useBookStore((state) => ({
books: state.books,
noOfAvailable: state.noOfAvailable,
noOfIssued: state.noOfIssued,
issueBook: state.issueBook,
returnBook: state.returnBook,
}));

return (
<ul className="book-list">
{!!books?.length && (
<span className="books-count">
<h4>Available: {noOfAvailable}</h4>
<h4>Issued: {noOfIssued}</h4>
</span>
)}
{books?.map((book) => {
return (
<Fragment key={book.id}>
<li className="list-item">
<span className="list-item-book">
<span>{book.id}</span>
<span>{book.name}</span>
<span>{book.author}</span>
</span>
<div className="btn-grp">
<button
onClick={() => issueBook(book.id)}
className={`issue-btn ${book.status === 'issued' ? 'disabled' : ''}`}
disabled={book.status === 'issued'}
>
{' '}
Issue{' '}
</button>
<button
onClick={() => returnBook(book.id)}
className={`return-btn ${book.status === 'available' ? 'disabled' : ''}`}
disabled={book.status === 'available'}
>
{' '}
Return{' '}
</button>
</div>
</li>
</Fragment>
);
})}
</ul>
);
}

export default BookList;
```
**BookList** ์ปดํฌ๋„ŒํŠธ๋Š” ๋„์„œ๊ด€์— ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๋ชจ๋“  ์ฑ…์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด์šฉ ๊ฐ€๋Šฅ ๋„์„œ์™€ ๋Œ€์ถœ๋œ ๋„์„œ์˜ ์ˆ˜๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋ชฉ๋ก์— ์žˆ๋Š” ๊ฐ ์ฑ… ๊ธฐ๋ก์—๋Š” **Issue**(๋Œ€์ถœ) ๋ฐ **Return**(๋ฐ˜๋‚ฉ) ๋ฒ„ํŠผ์ด ๋‘ ๊ฐœ ์žˆ์Šต๋‹ˆ๋‹ค. UI๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ž…๋‹ˆ๋‹ค.
<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*mzzOO6phLadV07DhRW4j-w.png"/>
์œ„ UI์—๋Š” ๋‘ ๊ถŒ์˜ ์ฑ…์ด ์žˆ์œผ๋ฉฐ, ๊ฐ ์ฑ… ๊ธฐ๋ก์— ๋Œ€ํ•ด **Issue** ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. **Return** ๋ฒ„ํŠผ์€ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ฑ…์ด ๋Œ€์ถœ๋˜์—ˆ์„ ๋•Œ๋งŒ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.
**Issue** ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด store์˜ **issueBook** ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฑ… ID๊ฐ€ ์ „๋‹ฌ๋˜๊ณ , ํ•ด๋‹น ์ฑ…์˜ ์ƒํƒœ๊ฐ€ '๋Œ€์ถœ๋จ(issued)'์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ, ๊ด€๋ จ๋œ **Issue** ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋˜๊ณ , **Return** ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฑ…์˜ ์ˆ˜๊ฐ€ ์ค„์–ด๋“ค๊ณ , ๋Œ€์ถœ๋œ ์ฑ…์˜ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์Šคํฌ๋ฆฐ์ƒท์„ ์ฐธ์กฐํ•˜์„ธ์š”.
<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*XmKsjPTJCcBU-cMeHrj8OQ.png"/>
**Return** ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด store์˜ **returnBook** ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฑ… ID๊ฐ€ ์ „๋‹ฌ๋˜๊ณ , ํ•ด๋‹น ์ฑ…์˜ ์ƒํƒœ๊ฐ€ '์ด์šฉ ๊ฐ€๋Šฅ(available)'์œผ๋กœ ๋‹ค์‹œ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ๊ด€๋ จ๋œ **Return** ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋˜๊ณ , **Issue** ๋ฒ„ํŠผ์ด ๋‹ค์‹œ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฑ…์˜ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ , ๋Œ€์ถœ๋œ ์ฑ…์˜ ์ˆ˜๊ฐ€ ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ์Šคํฌ๋ฆฐ์ƒท์„ ์ฐธ์กฐํ•˜์„ธ์š”.
> Zustand store๋Š” ํ›…(hook)์ด๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋””์„œ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Redux๋‚˜ Redux Toolkit๊ณผ๋Š” ๋‹ฌ๋ฆฌ context provider๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒํƒœ๋ฅผ ์„ ํƒํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด, ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ์Šฌ๋ผ์ด์Šค๋งŒ ์–ป๊ธฐ ์œ„ํ•ด **useBookStore**์— ์„ ํƒ๊ธฐ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์•„์ง ๋๋‚˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค! Zustand์—๋Š” ํฐ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค: **๋ฏธ๋“ค์›จ์–ด(Middlewares)**์ž…๋‹ˆ๋‹ค.
### Zustand ๋ฏธ๋“ค์›จ์–ด
Zustand๋Š” ๋ฏธ๋“ค์›จ์–ด์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” Zustand ๋ฏธ๋“ค์›จ์–ด๋Š” ์•„๋ž˜์— ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค.
1. **Redux DevTools**
Redux DevTools๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ๋””๋ฒ„๊ทธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Zustand์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Chrome ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ Redux DevTools๋ฅผ ์„ค์น˜ํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
```javascript
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

const bookStore = (set, get) => ({
books: [],
noOfAvailable: 0,
noOfIssued: 0,
addBook: (book) => {
set((state) => ({
books: [...state.books, { ...book, status: 'available' }],
noOfAvailable: state.noOfAvailable + 1,
}));
},
});

const useBookStore = create(devtools(bookStore));

export default useBookStore;
```
**devtools**๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด **zustand/middleware**์—์„œ ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ **create** ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ store๋ฅผ **devtools**๋กœ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.
์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ Redux DevTools๋ฅผ ์—ด๊ณ  ์ƒํƒœ๋ฅผ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์Šคํฌ๋ฆฐ์ƒท์— ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค.
<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*Tjau7gmPB8xsuMRfF08Ukw.png"/>
2. **Persist Middleware**
**Persist** ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์ข…๋ฅ˜์˜ ํด๋ผ์ด์–ธํŠธ ์ €์žฅ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์ง€์†์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ store์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ์†Œ์— ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋Š” ์•„๋ž˜๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.
```javascript
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

const bookStore = (set, get) => ({
books: [],
noOfAvailable: 0,
noOfIssued: 0,
addBook: (book) => {
set((state) => ({
books: [...state.books, { ...book, status: 'available' }],
noOfAvailable: state.noOfAvailable + 1,
}));
},
});

const useBookStore = create(
persist(bookStore, {
name: 'books',
storage: createJSONStorage(() => sessionStorage),
})
);

export default useBookStore;
```
**persist**๋ฅผ **zustand/middleware**์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ **create** ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ store๋ฅผ **persist**๋กœ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์ €์žฅ์†Œ์˜ ํ•ญ๋ชฉ์€ ๊ณ ์œ ํ•œ ์ด๋ฆ„์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ €์žฅ์†Œ์˜ ์ข…๋ฅ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ์—์„œ๋Š” **sessionStorage**๊ฐ€ ์ฐธ์กฐ๋ฉ๋‹ˆ๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ **localStorage**๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์—ด๊ณ  ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์—์„œ ์ €์žฅ๋œ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์„ธ์š”. ์Šคํฌ๋ฆฐ์ƒท์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
<img width="500px" src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*eVw9beZHm-3AgIJRF6XnGA.png"/>
### ์š”์•ฝ
์ด ๊ธ€์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ์ƒํƒœ ๊ด€๋ฆฌ๋Š” React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ปค์งˆ์ˆ˜๋ก ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ๊ฐ•๋ ฅํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Zustand ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” React ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์ด์ƒ์ ์ธ ํ•ด๊ฒฐ์ฑ…์ž…๋‹ˆ๋‹ค. Redux๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•˜๊ณ  ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๊ฐ€ ์ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ์˜ต์…˜์„ ํƒ์ƒ‰ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์Šต๋‹ˆ๋‹ค.
### ์ฐธ๊ณ 
1. https://docs.pmnd.rs/zustand/getting-started/introduction
2. https://www.youtube.com/watch?v=KCr-UNsM3vA
3. https://www.youtube.com/watch?v=fZPgBnL2x-Q

0 comments on commit 4f056bc

Please sign in to comment.