[๋ฐ๋ธŒ์ฝ”์Šค] React-Task-App: Redux์™€ ํƒ€์ž… ์•ˆ์ •์„ฑ

2025. 6. 17. 23:54ยท๐Ÿ•Š๏ธํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐ๋ธŒ์ฝ”์Šค/TIL

React Task App ํ”„๋กœ์ ํŠธ ์‹ค์Šต์— ๋“ค์–ด์™”๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ํŒŒํŠธ์— ์ง„์ž…ํ•˜์ž๋งˆ์ž C ์–ธ์–ด๋ฅผ ๋จผ์ € ๋‹ค๋ฃจ๊ณ , Typescirpt์™€ React ๊ฐœ๋…๋งŒ ๊ฐ„๋‹จํžˆ ์งš์€ ํ›„ ๊ณง๋ฐ”๋กœ ์‹ค์Šต์ด ์ง„ํ–‰๋˜์–ด ๋‹ค์†Œ ๋‹นํ™ฉ์Šค๋Ÿฝ๊ธฐ๋„ ํ•˜๋‹ค...์ด๋ก ์„ ์ถฉ๋ถ„ํžˆ ๋‹ค์งˆ ์‹œ๊ฐ„์ด ์žˆ์„ ์ค„ ์•Œ์•˜๋Š”๋ฐ, ์ƒ๊ฐ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์‹ค์ „ ์œ„์ฃผ๋กœ ๋“ค์–ด๊ฐ€๋Š” ๊ตฌ์„ฑ์ด๋ผ ๊ธด์žฅ๊ฐ์ด ๋„˜์น˜๋Š” ๋“ฏ.

 

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

 ๊ฐœ๋ฐœ์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ ๋ฐ ํŒŒ์ผ ์—ญํ• ๋“ค์„ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค.

 

๐Ÿ—‚๏ธcomponents/

  • UI๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋‹จ์œ„
  • ์ฃผ๋กœ Presentational / Dumb Component๋กœ ๋กœ์ง๋ณด๋‹ค UI ์ค‘์‹ฌ

๐Ÿ—‚๏ธ hooks/

  • React์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋กœ์ง ๋‹จ์œ„(useToggle, useFetch, useAuth ๋“ฑ)
  • ์ƒํƒœ ๊ด€๋ฆฌ, side effect ์ฒ˜๋ฆฌ ๋“ฑ์„ ์บก์Аํ™”

๐Ÿ—‚๏ธ store/

  • ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ
  • ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ณต์œ ํ•˜๋Š” ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ

๐Ÿ—‚๏ธ types/

  • typescript ํƒ€์ž… ์ •์˜ ๋ชจ์Œ
  • ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์—์„œ ์ผ๊ด€๋œ ํƒ€์ž… ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐Ÿ—‚๏ธ lib/, libs/

  • ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์ • ๋˜๋Š” ๋ž˜ํผ ํ•จ์ˆ˜
  • Axios ์ธ์Šคํ„ด์Šค, firebase ์„ค์ •, ๋‚ ์งœ ์ฒ˜๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ž˜ํผ ๋“ฑ ์™ธ๋ถ€ ๋„๊ตฌ์™€์˜ ์—ฐ๊ฒฐ ์ง€์ 

๐Ÿ—‚๏ธ utils/

  • ์ˆœ์ˆ˜ ํ•จ์ˆ˜ ๊ธฐ๋ฐ˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ชจ์Œ
  • ๋‚ ์งœ ํฌ๋งทํ„ฐ, ๋ฌธ์ž์—ด ํŒŒ์„œ, ๊ณ„์‚ฐ๊ธฐ ๋“ฑ ์ƒํƒœ๋‚˜ UI์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ๋ฒ”์šฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜

ํด๋” ๊ตฌ์กฐ


๐Ÿงฉ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ

src
โ”œโ”€โ”€ App.css
โ”œโ”€โ”€ App.tsx
โ”œโ”€โ”€ assets
โ”‚   โ””โ”€โ”€ react.svg
โ”œโ”€โ”€ components
โ”‚   โ”œโ”€โ”€ ActionButton
โ”‚   โ”‚   โ”œโ”€โ”€ DropDownForm
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”œโ”€โ”€ BoardList
โ”‚   โ”‚   โ”œโ”€โ”€ SideForm
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”œโ”€โ”€ EditModal
โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”œโ”€โ”€ List
โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”œโ”€โ”€ ListContainer
โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”œโ”€โ”€ LoggerModal
โ”‚   โ”‚   โ”œโ”€โ”€ LogItem
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ index.css.ts
โ”‚   โ”‚   โ””โ”€โ”€ index.tsx
โ”‚   โ””โ”€โ”€ Task
โ”‚       โ”œโ”€โ”€ index.css.ts
โ”‚       โ””โ”€โ”€ index.tsx
โ”œโ”€โ”€ hooks
โ”‚   โ””โ”€โ”€ redux.ts
โ”œโ”€โ”€ index.css
โ”œโ”€โ”€ main.tsx
โ”œโ”€โ”€ store
โ”‚   โ”œโ”€โ”€ index.ts
โ”‚   โ”œโ”€โ”€ reducer
โ”‚   โ”‚   โ””โ”€โ”€ reducer.ts
โ”‚   โ””โ”€โ”€ slices
โ”‚       โ”œโ”€โ”€ boardSlice.ts
โ”‚       โ”œโ”€โ”€ loggerSlice.ts
โ”‚       โ””โ”€โ”€ modalSlice.ts
โ””โ”€โ”€ types
    โ””โ”€โ”€ index.ts

18 directories, 32 files

๊ฐ•์‚ฌ๋‹˜๊ป˜์„œ๋Š” ํด๋” ํ•˜์œ„ ํŒŒ์ผ๋„ ํด๋”๋ช…๊ณผ ํ†ต์ผํ•˜์—ฌ ์ž‘์„ฑํ•˜์…จ๋‹ค(ex: List/List.tsx, List.css.ts).

 

๋‹ค๋งŒ ๋‚˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ํด๋” ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•œ ์‹œ์ ์—์„œ, ํ•ด๋‹น ํด๋” ์ž์ฒด๊ฐ€ ์ด๋ฏธ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค๊ณ  ๋ณด์•˜๋‹ค. ์ด๋Ÿฐ ๊ด€์ ์—์„œ, ํŒŒ์ผ๋ช…์— ๋‹ค์‹œ ํด๋”๋ช…์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ์ด ๋‹ค์†Œ ์ค‘๋ณต๋œ ํ‘œํ˜„์ฒ˜๋Ÿผ ๋А๊ปด์กŒ๋‹ค.

 

๊ทธ๋ž˜์„œ List/List.tsx ๋Œ€์‹  List/index.tsx ๊ตฌ์กฐ๋ฅผ ์„ ํƒํ–ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ import ๊ฒฝ๋กœ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ์ปดํฌ๋„ŒํŠธ์˜ ์ง„์ž…์ ์„ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚ธ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๋˜ํ•œ ์ด์ „ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ๋™์ผํ•œ ํด๋”๋ช…/index.tsx ๊ตฌ์กฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•ด ์™”๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐœ์ธ์ ์œผ๋กœ๋„ ๊ฐ€์žฅ ์ต์ˆ™ํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์ˆ˜์›”ํ•œ ๋ฐฉ์‹์ด์—ˆ๋‹ค.

 

์ด๋Ÿฐ ์ด์œ ๋กœ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ๊ตฌ์„ฑ์€ ํด๋” ๊ธฐ์ค€์œผ๋กœ ํ•˜๊ณ , ๋‚ด๋ถ€ ์ง„์ž… ํŒŒ์ผ์€ index.tsx๋กœ ํ†ต์ผํ•˜์—ฌ ๊ด€๋ฆฌํ•˜์˜€๋‹ค.


โฌ‡๏ธํŒจํ‚ค์ง€ ์„ค์น˜

  • @reduxjs/toolkit: Redux ๊ณต์‹ ํˆดํ‚ท
  • redux: ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ Redux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • clsx: ์กฐ๊ฑด๋ถ€ className์„ ๊น”๋”ํ•˜๊ฒŒ ์กฐํ•ฉํ•ด์ฃผ๋Š” ์œ ํ‹ธ
  • @vanilla-extract/css: css-in-typescript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • @vanilla-extract/css-utils: splinkles๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์Šคํƒ€์ผ ์‹œ์Šคํ…œ์„ ๊ตฌ์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ณด์กฐ ๋ชจ๋“ˆ
  • @vanilla-extract/vite-plugin: vite์—์„œ vanilla-extract๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋นŒ๋“œ ํ”Œ๋Ÿฌ๊ทธ์ธ
  • react-icons: ์•„์ด์ฝ˜ 
  • uuid: ๊ณ ์œ  ์‹๋ณ„์ž(UUID) ์ƒ์„ฑ ์œ ํ‹ธ
  • react-beautiful-dnd: ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ ์ธํ„ฐ๋ž™์…˜ ๊ตฌํ˜„์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

โŒ@vanilla-extract/vite-plugin ์˜์กด์„ฑ ์ถฉ๋Œ ๋ฌธ์ œ

vite๋ฅผ @latest๋กœ ์„ค์น˜ํ–ˆ๋Š”๋ฐ, @vanilla-extract/vite-plugin์€ vite@^5.0.0 || ^6.0.0 ๊นŒ์ง€๋งŒ ์ง€์›ํ•ด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์˜€๋‹ค.

 

โœ…ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:

vite ๋ฒ„์ „์„ ํ˜ธํ™˜ ๋ฒ„์ „์œผ๋กœ ๋‚ฎ์ท„๋‹ค.

npm install vite@^6

 

โŒreact-beautiful-dnd ์˜์กด์„ฑ ์ถฉ๋Œ ๋ฌธ์ œ

๋‘ ๋ฒˆ์งธ ์ถฉ๋Œ์€ react-beautiful-dnd๊ฐ€ react 19๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์•„์„œ ์ƒ๊ธด ์ถฉ๋Œ์ด๋‹ค(deprecated ๋จ).

 

โœ…ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:

๋Œ€์ฒด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, React ๋ฒ„์ „์„ ๋‚ฎ์ถ”์–ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์šฐ์„  ๊ฐ•์˜์™€ ์‹ค์Šต ํ™˜๊ฒฝ์„ ๋งž์ถ”๊ธฐ ์œ„ํ•ด react-beautiful-dnd๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๊ธฐ์— react๋ฅผ 18๋กœ ๋‚ฎ์ถ”์–ด ํ•ด๊ฒฐํ–ˆ๋‹ค.

npm install react@18 react-dom@18

 

ํ•ด๊ฒฐ!


โš›๏ธRedux ๊ธฐ๋ณธ ์„ค์ •

redux๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. React์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ props, state๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ์ƒํƒœ๊ฐ€ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์— ๋ถ„์‚ฐ๋˜๊ณ  ์˜์กด ๊ด€๊ณ„๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉด์„œ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์ง„๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Redux์™€ ๊ฐ™์€ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

Redux ํ๋ฆ„

Redux์˜ ํ•ต์‹ฌ ํŠน์ง•์€ ์ƒํƒœ ๋ณ€๊ฒฝ ํ๋ฆ„์ด ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„๋‹ค๋Š” ์ ์ด๋‹ค. 

์ปดํฌ๋„ŒํŠธ์—์„œ ํŠน์ • ๋™์ž‘์ด ๋ฐœ์ƒํ•˜๋ฉด, action์ด๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ์ด action์€ dispatch์˜ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด reducer๋กœ ์ „๋‹ฌ๋œ๋‹ค. reducer๋Š” ์ „๋‹ฌ๋ฐ›์€ action์˜ type์„ ๊ธฐ์ค€์œผ๋กœ ๊ธฐ์กด ์ƒํƒœ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด ๊ฒฐ๊ณผ๊ฐ€ redux store์— ์ €์žฅ๋œ๋‹ค.

 

์ด์ฒ˜๋Ÿผ ์ƒํƒœ๊ฐ€ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋‹จ์ผ ํ๋ฆ„์„ ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋˜๊ธฐ ๋•Œ๋ฌธ์—, store์˜ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ๋˜๋ฉด ํ•ด๋‹น ์ƒํƒœ๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ž๋™์œผ๋กœ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค. ์ด๋Š” ์ƒํƒœ ๋ณ€ํ™”์˜ ์›์ธ์„ ์ถ”์ ํ•˜๊ธฐ ์‰ฝ๊ณ , ๋””๋ฒ„๊น…์— ์œ ๋ฆฌํ•œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค.

 

Slice

Redux Toolkit์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, reducer๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๊ธฐ๋ณด๋‹ค๋Š” slice๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด ์ผ๋ฐ˜์ ์ด๋‹ค.

 

CreateSlice๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ดˆ๊ธฐ ์ƒํƒœ, reducer ๋กœ์ง, ๊ทธ๋ฆฌ๊ณ  action ์ƒ์„ฑ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด Redux๋ฅผ ๋ณด๋‹ค ๊ฐ„๊ฒฐํ•˜๊ณ  ์‹ค์šฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

import { createSlice } from "@reduxjs/toolkit";
import type { ITask } from "../../types";

type TModalState = {
    boardId : string;
    listId: string;
    task: ITask;
}
const initialState:TModalState = {
    boardId: "board-0", 
    listId: "list-0", 
    task:{
        taskId: "task-0",
        taskName: "task 0", 
        taskDescription: "task description",
        taskOwner: "John"
    }
}

const modalSlice = createSlice({
    name: 'modal', 
    initialState,
    reducers:{

    }
})

export const modalReducer = modalSlice.reducer;

๋จผ์ € createSlice๋ฅผ Redux Toolkit์—์„œ importํ•˜๊ณ , ๋ชจ๋‹ฌ์—์„œ ๋‹ค๋ฅธ task์˜ ์ •๋ณด ํƒ€์ž…์„ Itask ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๋ถˆ๋Ÿฌ์™”๋‹ค. ์ƒํƒœ์˜ ๊ตฌ์กฐ๋ฅผ ํƒ€์ž…์œผ๋กœ ๋ช…ํ™•ํžˆ ์ •์˜ํ•˜์—ฌ, ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ ํƒ€์ž…์˜ ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•จ.

 

initialState๋Š” Redux Store์— ์ €์žฅ๋  ์ดˆ๊ธฐ ์ƒํƒœ๊ฐ’์ด๋‹ค. ๋ชจ๋‹ฌ์€ ํŠน์ • task๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์—ด๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—, boardId, listId, task ์ •๋ณด๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋ชจ๋‹ฌ์ด ์—ด๋ฆด ๋•Œ action์„ ํ†ตํ•ด ์ด ๊ฐ’๋“ค์ด ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.

 

createSlice๋Š” slice์˜ ์ด๋ฆ„, ์ดˆ๊ธฐ ์ƒํƒœ, ๊ทธ๋ฆฌ๊ณ  ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” reducer ํ•จ์ˆ˜๋“ค์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด ์ •์˜ํ•œ๋‹ค. ํ˜„์žฌ๋Š” reducer๊ฐ€ ๋น„์–ด ์žˆ์ง€๋งŒ, ์ถ”ํ›„ ๋ชจ๋‹ฌ์„ ์—ด๊ฑฐ๋‚˜ ๋‹ซ๋Š” ๋™์ž‘ ๋“ฑ์˜ reducer์„ ์—ฌ๊ธฐ์— ์ถ”๊ฐ€ํ•œ๋‹ค.

 

๋งˆ์ง€๋ง‰์œผ๋กœ slice์—์„œ ์ƒ์„ฑ๋œ reducer์„ exportํ•˜์—ฌ, redux store์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. Redux Toolkit์„ ์‚ฌ์šฉํ•˜๋ฉด reducer์™€ action์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ํ•„์š” ์—†์ด, slice ๋‹จ์œ„๋กœ ์ƒํƒœ ๋กœ์ง์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ํฐ ์žฅ์ ์ด๋‹ค.

 

Redux Store ๊ตฌ์„ฑ

//redux store์šฉ ํŒŒ์ผ

import { configureStore } from "@reduxjs/toolkit";
import reducer from "./reducer/reducer";

const store = configureStore({
    reducer
})

export default store

redux toolkit์—์„œ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ํ•˜๋‚˜์˜ store์„ ์ƒ์„ฑํ•˜๊ณ , ์—ฌ๋Ÿฌ slice์—์„œ ์ •์˜ํ•œ reducer๋“ค์„ ์ด store์— ๋“ฑ๋กํ•œ๋‹ค.

 

configureStore๋Š” redux toolkit์—์„œ ์ œ๊ณตํ•˜๋Š” store ์ƒ์„ฑ ํ•จ์ˆ˜๋กœ, ๊ธฐ์กด redux์˜ createStore ๋ณด๋‹ค ์„ค์ •์ด ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ธฐ๋ณธ์ ์ธ ๋ฏธ๋“ค์›จ์–ด์™€ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์„ค์ •์ด ์ž๋™์œผ๋กœ ํฌํ•จ๋œ๋‹ค.

 

์ด ํŒŒ์ผ์—์„œ๋Š” store ์ƒ์„ฑ ์—ญํ• ๋งŒ ๋‹ด๋‹นํ•˜๋„๋ก ๊ตฌ์„ฑํ–ˆ๊ณ , ์‹ค์ œ reducer ์กฐํ•ฉ ๋กœ์ง์€ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ–ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด store์˜ ์„ค์ •๊ณผ ์ƒํƒœ ๊ตฌ์กฐ ์ •์˜๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์กŒ์„ ๋•Œ ๊ด€๋ฆฌํ•˜๊ธฐ ์ˆ˜์›”ํ•˜๋‹ค.

 

Root Reducer ๊ตฌ์„ฑ

import { boards } from "../slices/boardSlice";
import { loggerReducer } from "../slices/loggerSlice";
import { modalReducer } from "../slices/modalSlice";

const reducer = {
    logger: loggerReducer,
    boards: boards,
    modal: modalReducer
}

export default reducer;

์œ„ ์ฝ”๋“œ๋Š” ์—ฌ๋Ÿฌ slice์—์„œ ์ •์˜ํ•œ reducer๋“ค์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ๋Š” root reducer ์—ญํ• ์„ ํ•œ๋‹ค. ๊ฐ์ฒด์˜ ๊ฐ key๋Š” redux store์— ์ €์žฅ๋  ์ƒํƒœ์˜ ์ด๋ฆ„์ด ๋˜๋ฉฐ, value๋Š” ํ•ด๋‹น ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” reducer ํ•จ์ˆ˜์ด๋‹ค.

 

์ •๋ฆฌ

์ •๋ฆฌํ•˜๋ฉด, ์ตœ์ข… ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๊ฐ€ ๋œ๋‹ค.

state = {
  logger: ...,
  boards: ...,
  modal: ...
}
  • slice ๋‹จ์œ„๋กœ ์ƒํƒœ ๋กœ์ง์„ ๋ถ„๋ฆฌ-> ์ฑ…์ž„์ด ๋ช…ํ™•
  • reducer๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๊ด€๋ฆฌ->store ์„ค์ • ์ฝ”๋“œ๊ฐ€ ๋‹จ์ˆœํ•ด์ง
  • ์ƒํƒœ ๊ตฌ์กฐ๊ฐ€ ์ฝ”๋“œ๋กœ ๋ฐ”๋กœ ๋“œ๋Ÿฌ๋‚˜, useSelector ์‚ฌ์šฉ ์‹œ ์˜ˆ์ธก ๊ฐ€๋Šฅ

์œ„์™€ ๊ฐ™์€ ์„ค๊ณ„์  ์žฅ์ ์ด ์žˆ๋Š” ๊ตฌ์กฐ์ด๊ณ , ์ถ”ํ›„ slice๊ฐ€ ์ถ”๊ฐ€ ๋˜๋”๋ผ๋„ reducer ๊ฐ์ฒด์— ํ•ญ๋ชฉ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ™•์žฅ์„ฑ ์ธก๋ฉด์—์„œ ์œ ๋ฆฌํ•˜๋‹ค.


โš›๏ธRedux Hooks

// redux store์šฉ ํŒŒ์ผ
import { configureStore } from "@reduxjs/toolkit";
import reducer from "./reducer/reducer";

const store = configureStore({
    reducer
})

configureStore์„ ํ†ตํ•ด redux store์„ ์ƒ์„ฑํ•œ๋‹ค. ์ด ๋•Œ ์ „๋‹ฌํ•œ reducer ๊ฐ์ฒด์˜ ๊ตฌ์กฐ๊ฐ€ ์ „์—ญ ์ƒํƒœ ํŠธ๋ฆฌ์˜ ํ˜•ํƒœ๊ฐ€ ๋œ๋‹ค.

 

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
  • RootState: store.getState์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ „์—ญ ์ƒํƒœ์˜ ํƒ€์ž…์„ ์ž๋™์œผ๋กœ ์ถ”๋ก ํ•œ๋‹ค. reducer ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ํƒ€์ž…์„ ์ง์ ‘ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.
  • AppDispatch: store์—์„œ ์‚ฌ์šฉํ•˜๋Š” dispatch ํ•จ์ˆ˜์˜ ํƒ€์ž…์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์™€ ์ •์˜ํ•œ๋‹ค. ์ดํ›„ thunk๋‚˜ async action์ด ์ถ”๊ฐ€๋˜๋”๋ผ๋„ ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž… ์ถ”๋ก ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
import { useDispatch, useSelector, type TypedUseSelectorHook } from "react-redux";
import type { AppDispatch, RootState } from "../store";

๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต๋˜๋Š” useSelector, useDispatch๋Š” ํƒ€์ž… ์ •๋ณด๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ „์—ญ ํƒ€์ž…์„ ์ ์šฉํ•œ ์ปค์Šคํ…€ ํ›…์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜์˜€๋‹ค.

export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;

TypedUseSelectorHook<RootState>๋ฅผ ์‚ฌ์šฉํ•ด useSelector๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” state์˜ ํƒ€์ž…์„ RootState๋กœ ๊ณ ์ •ํ–ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์ปดํฌ๋„ŒํŠธ์—์„œ state๋ฅผ ์กฐํšŒํ•  ๋•Œ ์ž๋™ ์™„์„ฑ๊ณผ ํƒ€์ž… ์ฒดํฌ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.

export const useTypedDispatch = () => useDispatch<AppDispatch>();

useDispatch ์—ญ์‹œ AppDispatch ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ ์šฉํ–ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด dispatch ์‹œ ์ž˜๋ชป๋œ action์ด๋‚˜ payload๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์‹ค์ˆ˜๋ฅผ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.


 

ํ”„๋กœ์ ํŠธ ์„ธํŒ… ๋‹จ๊ณ„๋ผ ๋ฐฉ์‹ฌํ–ˆ๋Š”๋ฐ ํ›„๋ฐ˜์œผ๋กœ ๊ฐˆ์ˆ˜๋ก ํƒ€์ž… ๊ด€๋ จ ๋‚ด์šฉ๋“ค์ด ํ•œ๊บผ๋ฒˆ์— ๋“ฑ์žฅํ•˜๋ฉด์„œ ์ฒด๊ฐ ๋‚œ์ด๋„๊ฐ€ ํ™• ์˜ฌ๋ผ๊ฐ„๋“ฏ...redux์™€ typescript๋ฅผ ํ•จ๊ป˜ ์ ์šฉํ•ด, ๋‹จ์ˆœํžˆ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ ์ด์ƒ์œผ๋กœ ํƒ€์ž… ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋” ๋งŽ์€ ์—๋„ˆ์ง€๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ๋А๊ปด์ง„๋‹ค..

 

ํƒ€์ž… ๋•Œ๋ฌธ์— ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ์ˆœ๊ฐ„๋„ ์žˆ์—ˆ์ง€๋งŒ, Redux์˜ ์ „์ฒด์ ์ธ ํ๋ฆ„๊ณผ Rootstate, Dispatch ํƒ€์ž…์„ ํ†ตํ•ด ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

'๐Ÿ•Š๏ธํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐ๋ธŒ์ฝ”์Šค > TIL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[๋ฐ๋ธŒ์ฝ”์Šค] book store 2  (0) 2025.06.23
[๋ฐ๋ธŒ์ฝ”์Šค] React-Task-App: configureStore ์‹ฌ์ธต ๋ถ„์„ ๋ฐ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ ๊ณผ์ •์—์„œ์˜ ํƒ€์ž… ํ™œ์šฉ ์ •๋ฆฌ  (0) 2025.06.21
[๋ฐ๋ธŒ์ฝ”์Šค] Redux  (2) 2025.06.16
[๋ฐ๋ธŒ์ฝ”์Šค] React ๊ธฐ์ดˆ ํ•ต์‹ฌ ์ •๋ฆฌ(state, ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น, ์ปดํฌ๋„ŒํŠธ ๋ฐ˜๋ณต)  (2) 2025.06.15
[๋ฐ๋ธŒ์ฝ”์Šค] React์™€ JSX, UI ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ์ „ํ™˜  (1) 2025.06.14
'๐Ÿ•Š๏ธํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐ๋ธŒ์ฝ”์Šค/TIL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [๋ฐ๋ธŒ์ฝ”์Šค] book store 2
  • [๋ฐ๋ธŒ์ฝ”์Šค] React-Task-App: configureStore ์‹ฌ์ธต ๋ถ„์„ ๋ฐ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ ๊ณผ์ •์—์„œ์˜ ํƒ€์ž… ํ™œ์šฉ ์ •๋ฆฌ
  • [๋ฐ๋ธŒ์ฝ”์Šค] Redux
  • [๋ฐ๋ธŒ์ฝ”์Šค] React ๊ธฐ์ดˆ ํ•ต์‹ฌ ์ •๋ฆฌ(state, ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น, ์ปดํฌ๋„ŒํŠธ ๋ฐ˜๋ณต)
ํ‚ํ‚์ž‰
ํ‚ํ‚์ž‰
  • ํ‚ํ‚์ž‰
    monicx.dev
    ํ‚ํ‚์ž‰
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (181)
      • ๐Ÿ–ฅ๏ธdevelop (15)
        • Github (2)
        • Frontend (4)
        • Backend (5)
        • Mobile (0)
        • CS (0)
        • Three.js (0)
        • Docker (2)
      • ๐Ÿ“šbook (9)
        • npm Deep Dive (4)
      • ๐Ÿ“•review (39)
        • ์ฑ… (27)
        • ํ–‰์‚ฌ (1)
        • ํšŒ๊ณ  (2)
      • โญproject (5)
        • petiary (2)
        • ๆšŽ่ฉ  (0)
        • ์ธํ„ด (2)
      • ๐Ÿ˜ถ‍๐ŸŒซ๏ธalgorithm (0)
      • ๐Ÿ’กtips (2)
      • ๐Ÿ˜Ždaily (10)
      • ๐Ÿ•น๏ธgame (0)
      • ๐Ÿ•Š๏ธํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐ๋ธŒ์ฝ”์Šค (87)
        • TIL (62)
        • ํ”„๋กœ์ ํŠธ (17)
        • ํšŒ๊ณ  (8)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
  • ๋งํฌ

    • ๋ฒจ๋กœ๊ทธ
  • ์ธ๊ธฐ ๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
ํ‚ํ‚์ž‰
[๋ฐ๋ธŒ์ฝ”์Šค] React-Task-App: Redux์™€ ํƒ€์ž… ์•ˆ์ •์„ฑ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”