Redux-Saga

๊น€์˜์žฌยท2021๋…„ 11์›” 11์ผ
2
post-thumbnail

Redux-Saga๋ž€?

๋ฆฌ๋•์Šค ์‚ฌ๊ฐ€๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์ฒ˜๋Ÿผ ๋ฆฌ๋“€์„œ์—์„œ ์ฒ˜๋ฆฌํ•˜๋ฉด ์•ˆ๋˜๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฆฌ๋•์Šค ๋ฏธ๋“ค์›จ์–ด ์ž…๋‹ˆ๋‹ค. Redux-Saga๋Š” ์ผ๋ฐ˜ action์„ dispatchํ•˜๊ณ  Generator๋ผ๋Š” ๊ฒƒ์„ ํ†ตํ•ด function*๊ณผ ๊ฐ™์€ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์„ธํŒ…๋ฐฉ๋ฒ•

npm i redux-saga

Redux-Saga ์กฐ๊ธˆ๋” ์ž์„ธํžˆ

๋ฆฌ๋•์Šค ์‚ฌ๊ฐ€๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ side Effect๋ฅผ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•˜๊ณ , ์‹คํ–‰ํ•˜๊ธฐ ์‰ฝ๊ณ , ์˜ค๋ฅ˜๋ฅผ ๋” ์ž˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœํ•˜๋Š” ๋ฆฌ๋•์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.

Generators ๋ผ๋Š” ES6์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ํ๋ฆ„์„ ์‰ฝ๊ฒŒ ์ฝ๊ณ  ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜์—ฌ ๋น„๋™๊ธฐ ํ๋ฆ„์„ ํ‘œ์ค€ ๋™๊ธฐ JavaScript์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ Side Effect๋Š” ๋ถ€์ž‘์šฉ์ด ์•„๋‹Œ ๋ถ€์ˆ˜ ์ž‘์šฉ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

Generator, Generator function, Effect

๋ฆฌ๋•์Šค ์‚ฌ๊ฐ€๋ฅผ ํ•™์Šตํ•˜๋‹ค๋ณด๋ฉด ๊ณ„์†ํ•ด์„œ ๋”ฐ๋ผ๋‚˜์˜ค๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์™€ ์ œ๋„ˆ๋ ˆ์ดํ„ฐํ•จ์ˆ˜์ด๋‹ค.

์šฐ์„  ์‚ฌ๊ฐ€๋ฅผ ์ง์ ‘์ ์œผ๋กœ ๊ณต๋ถ€ํ•˜๊ธฐ์ „ ์‚ฌ๊ฐ€์˜ ๊ธฐ๋ณธ ๋™์ž‘์›๋ฆฌ์ธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์— ๊ด€๋ จํ•˜์—ฌ ํ•™์Šตํ•ด์•ผํ•œ๋‹ค.

Generator, Generator function

Redux-Saga์—์„œ Saga๊ฐ€ ๋ฐ”๋กœ ์ œ๋„ˆ๋ ˆ์ดํ„ฐํ•จ์ˆ˜(์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์•„๋‹˜)์ด๋‹ค.

๊ฐ„๋‹จํžˆ ๋งํ•˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜์ด๋‹ค.

function* generateFunction(){
	 yield 1;
	 yield 2;
	 yield 3;
}

const generator = generateFunction();

console.log(generator.next().value); //1
console.log(generator.next().value); //2
console.log(generator.next().value); //3

์œ„์˜ ์ฝ”๋“œ์—์„œ function*์ด ์ œ๋„ˆ๋ ˆ์ดํ„ฐํ•จ์ˆ˜(์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์•„๋‹ˆ๋‹ค!)๋‹ค. ์ด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ์‹œ ๋ฐ˜ํ™˜๋˜๋Š”

๊ฐ์ฒด๊ฐ€ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ์ด๋‹ค. mdn๋งŒ ์ฐพ์•„๋ด๋„ ์ฒซ์ค„์— ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ๋ฐ˜ํ™˜๊ฐ’์ด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ผ๊ณ  ์†Œ๊ฐœํ•œ๋‹ค.

์ด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ 3๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„๋‹ค.

Generator.prototype.next()

  • yield๋ผ๋Š” ํ‘œํ˜„์„ ํ†ตํ•ด yield๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Generator.prototype.return()

  • ์ฃผ์–ด์ง„ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ  ์ƒ์„ฑ๊ธฐ๋ฅผ ์ข…๋ฃŒํ•จ

Generator.prototype.throw()

  • ์ƒ์„ฑ๊ธฐ๋กœ ์—๋Ÿฌ๋ฅผ throwํ•œ๋‹ค.

์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ(Iterator) ํ”„๋กœํ† ์ฝœ๊ณผ ์ดํ„ฐ๋Ÿฌ๋ธ”(Iterable)ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅธ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ์ดํ„ฐ๋Ÿฌ๋ธ”๊ณผ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

์ดํ„ฐ๋Ÿฌ๋ธ”(Iterable)

Symbol.iterator ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋Š” for of ๋ฌธ์œผ๋กœ ์ˆœํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ๋Š” Array๊ฐ์ฒด๊ฐ€์žˆ๋‹ค.

const array = [1,2,3,4,5];

console.log(Symbol.iterator in array); //true

for (const item of array ) {
	console.log(item) //1,2,3,4,5
}

์ข€๋” ์„ค๋ช…ํ•˜์ž๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์€ ๋‹จ์ˆœํžˆ ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„๋œ๋‹ค.

obj[Symbol.iterator]: Function => Iterator

๊ฐ์ฒด๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์‹ฌ๋ณผ ํ‚ค๊ฐ’์— ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค.

์ดํ„ฐ๋ ˆ์ดํ„ฐ(Iterator)

์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด์—์„œ Symbol.Iterator๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด iterator๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋ฐ˜ํ™˜๋œ iterator๊ฐ์ฒด๋Š” next๋ฉ”์„œ๋“œ๋ฅผ ์†Œ์œ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ IteratorResult๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

iteratorResult๋Š” value์™€ done ์„ ํ”„๋กœํผํ‹ฐ๋กœ ๊ฐ€์ง„๋‹ค.

์—ฌ๊ธฐ์„œ value๋Š” ํ˜„์žฌ ์ˆœํšŒํ•˜๋Š” ๊ฐ’์„ ๊ฐ–๊ณ ์žˆ๊ณ  done์€ ์ˆœํšŒ๊ฐ€ ์–ธ์ œ ๋๋‚˜๋Š”์ง€ ์•Œ๋ ค์ค€๋‹ค.

next๋ฉ”์„œ๋“œ๋Š” ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋‹ค ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉด value๋Š” undefined๋ฅผ

doneํ”„๋กœํผํ‹ฐ๋Š” true๊ฐ€ ๋˜๋ฉฐ ์ˆœํšŒ๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.

const array = [1,2,3,4,5]

const iterator = array[Symbol.iterator]()

console.log(iterator.next());  //{ value: 1, done: false }
console.log(iterator.next());  //{ value: 2, done: false }
console.log(iterator.next());  //{ value: 3, done: false }
console.log(iterator.next());  //{ value: 4, done: false }
console.log(iterator.next());  //{ value: 5, done: false }
console.log(iterator.next());  //{ value: undefined, done: true }

๋‹ค์‹œ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ, ์ œ๋„ˆ๋ ˆ์ดํ„ฐํ•จ์ˆ˜๋กœ ๋Œ์•„๊ฐ€๋ณด์ž.

์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ ๋ฆฌ๋•์Šค ์‚ฌ๊ฐ€์—์„œ ์‚ฌ๊ฐ€๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์ด๊ณ  ๋ฏธ๋“ค์›จ์–ด๋Š” saga์—๊ฒŒ yield๊ฐ’์„ ๋ฐ›์•„ ๋˜๋‹ค๋ฅธ ์–ด๋–ค ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
์‚ฌ๊ฐ€๋Š” ๋ฏธ๋“ค์›จ์–ด์— ๋ช…๋ น์„ ๋‚ด๋ฆฌ๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์‹ค์ œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ๋™์ž‘์€
๋ฏธ๋“ค์›จ์–ด์—์„œ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์กฐ๊ธˆ๋” ์ž์„ธํžˆ ๋งํ•˜๋ฉด ์‚ฌ๊ฐ€๋Š” ๋ฏธ๋“ค์›จ์–ด์— ์ดํŽ™ํŠธ๋ฅผ ํ™œ์šฉํ•ด ์–ด๋– ํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํ•˜๋„๋ก ๋ช…๋ น์„ ๋‚ด๋ฆฌ๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์ง์ ‘์ ์ธ ๋น„๋™๊ธฐ ์ž‘์—… ๋ฐ side Effect๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ณณ์€ ๋ฏธ๋“ค์›จ์–ด์ด๋ฉฐ ์ด ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋™์ž‘ํ•œ ํ›„ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฐ˜ํ™˜๊ฐ’์ด ๋‹ค์‹œ ์‚ฌ๊ฐ€์—๊ฒŒ ๋Œ์•„์˜ค๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋ ‡๊ธฐ ๋•Œ๋ฌธ์— saga์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์•„๋ฌด๋ฆฌ ๋ณต์žกํ•ด๋„ ๋Œ€๋ถ€๋ถ„ if, else, for์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ดํŽ™ํŠธ (Effect)

์ดํŽ™ํŠธ๋Š” ๋ฏธ๋“ค์›จ์–ด์— ์˜ํ•ด ์ˆ˜ํ–‰๋˜์•ผํ•˜๋Š” ๋ช…๋ น์„ ๋‹ด๊ณ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์ด๋‹ค.

์ดํŽ™ํŠธ ์ƒ์„ฑ์ž๋Š” ์ผ๋ฐ˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ๋งŒ ํ•˜๊ณ  ์–ด๋– ํ•œ ๋™์ž‘๋„ ํ•˜์ง€์•Š๋Š”๋‹ค.

์‚ฌ๊ฐ€๋Š” ์ด๋Ÿฐ ๋ช…๋ น์„ ๋‹ด๊ณ ์žˆ๋Š” ์ดํŽ™ํŠธ๋ผ๋Š” ๊ฐ์ฒด๋ฅผ yieldํ•  ๊ฒƒ์ด๊ณ  ๋ฏธ๋“ค์›จ์–ด๋Š” ์ด๋Ÿฌํ•œ ๋ช…๋ น์„ ๋ฐ”ํƒ•์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ๊ทธ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ๊ฐ€์—๊ฒŒ ๋Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ œ ์–ด๋–ค ์ดํŽ™ํŠธ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์ž.

takeEvery(action, sagaFn)

  • action์ด ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค Task๊ฐ€ ์‹คํ–‰๋˜๊ฒŒํ•œ๋‹ค.
  • ์—ฌ๋Ÿฌ Task๋ฅผ ๋™์‹œ์— ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฆฌ๋•์Šค ์„ฑํฌ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค.

takeLatest(action, sagaFn)

  • ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐœ์ƒํ•œ ํ•˜๋‚˜์˜ action์—๋งŒ Task๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • ์‹คํ–‰์ค‘์ด๋˜ Task๋Š” action์ด ๋ฐœ์ƒํ•˜๋ฉด ์ทจ์†Œ๋˜๊ณ  ์ƒˆ๋กœ์šด Task๊ฐ€ ์‹คํ–‰๋จ.

select

  • state์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊บผ๋‚ด์˜จ๋‹ค.

put

  • Action์„ Dispatchํ•œ๋‹ค.

take

  • ์•ก์…˜ / ์ด๋ฒคํŠธ ๋ฐœ์ƒ์„ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

call(fn,...args)

  • Promise์˜ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

fork

  • ๋‹ค๋ฅธ Task๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.

join

  • ๋‹ค๋ฅธ Task์˜ ์ข…๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

ํƒœ์Šคํฌ(Task)

ํ•˜๋‚˜์˜ saga๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํƒœ์Šคํฌ๋ผ๊ณ  ํ•œ๋‹ค.

Redux-Saga ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ

์‚ฌ๊ฐ€๋ฅผ ํ™œ์šฉํ•ด์„œ ๋ช‡๊ฐ€์ง€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

์ฒซ๋ฒˆ์งธ๋กœ ๋‚ ์”จ API๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฒ ๋‹ค.

// store/modules/weather.js

import { createAction, createReducer } from '@reduxjs/toolkit';

export const GET_WEATHER = 'weather/GET_WEATHER';
export const GET_WEATHER_SUCCESS = 'weather/GET_WEATHER_SUCCESS';
export const GET_WEATHER_FAILURE = 'weather/GET_WEATHER_FAILURE';
export const GET_WEATHER_LOADING = 'weather/GET_WEATHER_LOADING';

export const getWeather = createAction(GET_WEATHER);
export const getWeatherSuccess = createAction(GET_WEATHER_SUCCESS);
export const getWeatherFailure = createAction(GET_WEATHER_FAILURE);
export const getWeatherLoading = createAction(GET_WEATHER_LOADING);

const initialState = {
  isLoading: false,
  weatherData: []
};

const reducer = createReducer(initialState, {
  [getWeatherLoading]: (state) => {
    state.isLoading = true;
  },
  [getWeatherSuccess]: (state, action) => {
    (state.isLoading = false), (state.weatherData = action.payload);
  },
  [getWeatherFailure]: (state) => {
    state;
  }
});

export default reducer;

์•ก์…˜๊ณผ ๋ฆฌ๋“€์„œ์—๋Š” ํŠน๋ณ„ํžˆ ๋ˆˆ์— ๋„๋Š”๊ฒŒ ์—†๋‹ค.

๋‚ ์”จAPI๋ฐ›์•„์˜ฌ๋•Œ ์„ฑ๊ณต,์‹คํŒจ,๋กœ๋”ฉ์ƒํ™ฉ์— ๋Œ€ํ•ด ์•ก์…˜๊ณผ ๋ฆฌ๋“€์„œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์—ˆ๋‹ค.

// store/api.js

// weather API
const API = {
  key: '062f94b6879d4a4a64755999bee3a513',
  base: 'https://api.openweathermap.org/data/2.5/'
};

export function getWeatherApi() {
  return axios.get(`${API.base}${query}${API.key}`);
}

์œ„์˜ ์ฝ”๋“œ์—์„œ ํ•ด๋‹น API๋ฅผ fetchingํ•œ๋‹ค.

// store/sagas/weather.js

import { put, call, takeEvery, fork } from 'redux-saga/effects';
import * as actions from '../modules/weather';
import { getWeatherApi } from '../api';  --(1)

function* getWeather() {
  try {
    const response = yield call(getWeatherApi); --(2)
    yield put(actions.getWeatherSuccess(response));
  } catch (err) { --(3)
    yield put(actions.getWeatherFailure(err));
  }
}

function* watchGetWeather() {
  yield takeEvery(actions.GET_WEATHER, getWeather); --(4)
}

export default function* watchSaga() {
  yield fork(watchGetWeather);
}

(1) : API.js์—์„œ api๋ฅผ fetchingํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

(2) : Promise์˜ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ์œ„ํ•ด ๊ด€๋ จ ์ดํŽ™ํŠธ์ธ call์„ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

(3) : api fetching์‹คํŒจํ–ˆ์„๋•Œ์˜ ์ƒํ™ฉ์„ ์œ„ํ•ด ์ƒ์„ฑํ•œ ๋ฆฌ๋“€์„œ๋ฅผ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

(4) : getWeather์—์„œ ๋ฏธ๋“ค์›จ์–ด์—์„œ ์ˆ˜ํ–‰ํ•œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ ๊ฐ’์„ (4)์—์„œ ๋‹ค์‹œ ๋Œ๋ ค๋ฐ›์Šต๋‹ˆ๋‹ค.

// store/sagas/index.js

import { all, fork } from 'redux-saga/effects';
import weather from './weather';
import ...

export default function* rootSaga() {
  yield all([fork(weather), ...]);
}

combineReducer์ฒ˜๋Ÿผ saga์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฃจํŠธ ์‚ฌ๊ฐ€์— ํ•œ๋ฒˆ์— ๋‹ด์•„์„œ ์Šคํ† ์–ด์— ๋ณด๋ƒ…๋‹ˆ๋‹ค.

//store/store.js

import createSagaMiddleware from 'redux-saga';
import logger from 'redux-logger';
import index from './modules/index';
import rootSaga from './sagas/index';
import { configureStore } from '@reduxjs/toolkit';

const sagaMiddleware = createSagaMiddleware();
const middlewares = [logger, sagaMiddleware];

export const store = configureStore({
  devTools: false,
  middleware: middlewares,
  reducer: index
});

sagaMiddleware.run(rootSaga);

์ด๋Ÿฐ์‹์œผ๋กœ rootSaga๋ฅผ store๋กœ importํ•ด์™€์„œ ๋ฏธ๋“ค์›จ์–ด ๋™์ž‘์„ ์œ„ํ•ด createMiddleware ๊ทธ๋ฆฌ๊ณ 

๋ณด๋‹ค ๋ช…ํ™•ํžˆ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์—์„œ ํ™•์ธ์„ ์œ„ํ•ด logger๋ฅผ importํ•ด์˜ต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‚œ ํ›„ sagaMiddleware.run(rootSaga)๋ฅผ ํ†ตํ•˜์—ฌ ๋ชจ๋“  ์‚ฌ๊ฐ€ ์ปดํผ๋„ŒํŠธ ๊ฒฐ๊ณผ๋ฅผ ์‹คํ–‰์‹œํ‚ต๋‹ˆ๋‹ค.

์‹คํ–‰์ค‘์ธ ํ”„๋กœ์ ํŠธ์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ ์ฝ˜์†”์ฐฝ์—์„œ ๋ฆฌ๋•์Šค ๋กœ๊ฑฐ๋ฅผ ํ†ตํ•˜์—ฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์™€ ๊ฐ™์ด ์›ํ•˜๋Š” weather API data์ •๋ณด๊ฐ€ ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

profile
[ frontend-developer ]

0๊ฐœ์˜ ๋Œ“๊ธ€