Redux: Egghead์˜ Redux ์Šคํฌ๋ฆฐ์บ์ŠคํŠธ ์‹œ๋ฆฌ์ฆˆ

์— ๋งŒ๋“  2015๋…„ 11์›” 24์ผ  ยท  69์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: reduxjs/redux

Redux ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ํŒ”๋กœ์šฐํ•˜๊ณ  ์žˆ์ง€๋งŒ ์•„์ง ์ž์„ธํžˆ ๋‹ค๋ฃจ์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๊ธฐ๋ณธ์ ์ธ ์ธก๋ฉด์— ๋Œ€ํ•ด ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•œ๋‹ค๋ฉด Egghead๊ฐ€ ๋‚ด Redux ์‹œ์ž‘ํ•˜๊ธฐ ์‹œ๋ฆฌ์ฆˆ๋ฅผ ์ถœํŒํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ ๋˜์–ด ๊ธฐ์  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์„œ์˜ "๊ธฐ๋ณธ" ๋ถ€๋ถ„๊ณผ ๋™์ผํ•œ ์ฃผ์ œ๋ฅผ ๋‹ค๋ฃจ์ง€๋งŒ ์กฐ๊ธˆ ๋” ๊นŠ์ด ํŒŒ๊ณ ๋“ค์–ด Redux ๊ธฐ๋ณธ ์‚ฌํ•ญ์„ _์ •๋ง__ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” ๊ตฌ๋…์ž ์ „์šฉ Redux on Egghead์— ๋Œ€ํ•ด ๋” ๋งŽ์€ ์ฝ˜ํ…์ธ ๋ฅผ ๋งŒ๋“ค ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋” ๊ณ ๊ธ‰ ์ฃผ์ œ๋ฅผ ๋‹ค๋ฃฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ œ์•ˆ ์‚ฌํ•ญ์ด ์žˆ์œผ๋ฉด ์ด ์Šค๋ ˆ๋“œ์—์„œ ์•Œ๋ ค์ฃผ์„ธ์š”!

feedback wanted

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@markerikson ์ด ์งˆ๋ฌธ์— ๋Œ€ํ•ด ํ•จ๊ป˜

์ฐธ๊ณ : ํŽธ์˜๋ฅผ ์œ„ํ•ด thunk ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ๋กœ redux-thunk์ด๋“  redux-promise์ด๋“  ๊ฐ„์— ๋น„๋™๊ธฐ์— ๋Œ€ํ•œ ์ž„์˜์˜ ๋ฏธ๋“ค์›จ์–ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

UI ๋ ˆ์ด์–ด๋Š” ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์„ ํ•ธ๋“ค๋Ÿฌ์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด UI๊ฐ€ _some_ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์กฐ์ž‘๋ฉ๋‹ˆ๋‹ค. ์ข…์ข… ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ด๋Ÿฌํ•œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ props๋กœ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐ”์ธ๋”ฉ๋œ ์ž‘์—… ์ƒ์„ฑ์ž์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. UI๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. --- ๊ทธ๋ƒฅ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

"ํ•ธ๋“ค๋Ÿฌ"๊ฐ€ (๋ฏธ๋“ค์›จ์–ด์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋ ) ํ•จ์ˆ˜๋ฅผ ๋””์ŠคํŒจ์น˜ํ•˜๋Š”์ง€ ๋˜๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ์‹คํ–‰ํ•˜๊ณ  _then_์ด ์ผ๋ฐ˜ ์ž‘์—…์„ ๋””์ŠคํŒจ์น˜ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” UI ๋ ˆ์ด์–ด์— ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. --- UI๋Š” ์™„์ „ํžˆ ๋ถˆ๊ฐ€์ง€๋ก ์ ์ž…๋‹ˆ๋‹ค. _๊ฐ€๋Šฅ_ ๋ถˆ๊ฐ€์ง€๋ก ์ ์ผ ์ˆ˜ ์žˆ์Œ)

์ฝํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด "์•ฑ"์˜ ๋งŽ์€ ๋ถ€๋ถ„์ด ์ด๋Ÿฌํ•œ "์ฒ˜๋ฆฌ๊ธฐ"์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ react/redux ์•ฑ์—์„œ ์ด๋Ÿฌํ•œ "ํ•ธ๋“ค๋Ÿฌ"๋Š” ์ข…์ข… ์ผ์ข…์˜ ์•ก์…˜ ์ƒ์„ฑ์ž์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๋น„๋™๊ธฐ ํ•ญ๋ชฉ์„ ์ฝํฌ๋กœ ์ž‘์„ฑํ•˜๊ณ  ๋ฐœ์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ๋ชจ๋“  ๋น„๋™๊ธฐ ํ•ญ๋ชฉ์„ dispatch ์ธ์ˆ˜๋กœ ํ—ˆ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ด€์ ์—์„œ ๋ณผ ๋•Œ someHandler(dispatch) OR dispatch(someHandler()) ๋˜๋Š” ์ƒ์œ„์—์„œ ์ƒ์†๋œ ๋ฐ”์ธ๋”ฉ๋œ ์ž‘์—… ์ž‘์„ฑ์ž์˜ ๊ฒฝ์šฐ ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ someHandler() ์ž…๋‹ˆ๋‹ค. UI ๋ ˆ์ด์–ด์™€ ์ด ์ฐจ์ด๋ฅผ ์™„์ „ํžˆ ๊ฐ€๋ฆฌ๋Š” bindActionCreators ๋ฒ„์ „์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ก์…˜ ์ œ์ž‘์ž๋กœ ์ž‘์„ฑ๋œ react/redux ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ œ๊ณตํ•˜๋ฉด UI ๊ณ„์ธต์„ _๊ทผ๋ณธ์ ์œผ๋กœ_ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ ๋„ redux-thunk๋ฅผ ์™„์ „ํžˆ ๊ต์ฒดํ•˜๊ณ  ๋น„ ๋ฏธ๋“ค์›จ์–ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ฐธ๊ณ : getState ์„ ์ฃผ์ž…ํ•˜๋Š” ์œ„์น˜/๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ  ์žˆ์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ๋Š” ์‚ฌ์†Œํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด๋ผ๊ณ  _๋ฏฟ์Šต๋‹ˆ๋‹ค_).

๋”ฐ๋ผ์„œ '๋‚ด๋ถ€'์™€ '์™ธ๋ถ€'์˜ ๊ตฌ๋ถ„์ด '์•ฑ ์ˆ˜์ค€' ๋˜๋Š” 'UI ์ˆ˜์ค€'์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ๋ฐ›์•„๋“ค์ด๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ† ๋ก ์— ๊ฐ์‚ฌ๋“œ๋ฆฌ๋ฉฐ ๋ถ€์ •์ ์ธ ์˜๊ฒฌ์ด ๋‚˜์˜ค์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋ชจ๋“  69 ๋Œ“๊ธ€

:+1:

  1. ๋กœ์ปฌ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ƒํƒœ ๋Œ€ ์ „์—ญ ์ƒํƒœ
  2. ์—ฌ๋Ÿฌ ๋ฆฌ๋“€์„œ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๋Š” ์•ก์…˜ ๋Œ€ 1:1 ์•ก์…˜ ๋ฆฌ๋“€์„œ ๊ด€๊ณ„
  3. ์ฒซ ๋ฒˆ์งธ ์ž‘์—…์ด ์™„๋ฃŒ๋œ ์งํ›„ ๋‘ ๋ฒˆ์งธ ์ž‘์—…์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ž‘์—… ์ฒด์ธ(ํŠนํžˆ ๋น„๋™๊ธฐ ์ž‘์—… ์ฒด์ธ) ์ฒ˜๋ฆฌ.
  4. ๋ถˆํ•„์š”ํ•œ ์žฌ์žฌ์ƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์ ํ™” ๊ธฐ์ˆ (์ผ๊ด„ ์ฒ˜๋ฆฌ, ์žฌ์„ ํƒ ๋“ฑ).

:+1:

์‹œ๋ฆฌ์ฆˆ์˜ ์ฒ˜์Œ 16๊ฐœ ์—ํ”ผ์†Œ๋“œ๋ฅผ ๋ฐฉ๊ธˆ ๋ณด์•˜๊ณ  ๋‚ด๊ฐ€ ์ผํ•˜๋Š” ํšŒ์‚ฌ์—์„œ ๋‚ด๋ถ€ ๊ต์œก์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ›Œ๋ฅญํ•œ ๋ฆฌ์†Œ์Šค๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒํƒœ ํŠธ๋ฆฌ์— ๋Œ€ํ•ด ์ผ๋ฐ˜ ๊ฐ์ฒด์™€ deep-freeze ๋งŒ ์‚ฌ์šฉํ•˜๊ณ  immutable-js ์™€ ๊ฐ™์€

์ด์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์ƒ๊ฐ์„ ์•„๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ฏน์Šค์— Immutable์„ ๋˜์ง€๋ฉด Redux์™€ Immutable API๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์›Œ์•ผ ํ•˜๊ฑฐ๋‚˜ Immutable์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๋“ฑ ์ดˆ๋ณด์ž๋ฅผ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ๊ณ ๊ธ‰ ๋ ˆ์Šจ์„ ์œ„ํ•œ ์ข‹์€ ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค!

๋ฏน์Šค์— Immutable์„ ๋˜์ง€๋ฉด Redux์™€ Immutable API๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์›Œ์•ผ ํ•˜๊ฑฐ๋‚˜ Immutable์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๋“ฑ ์ดˆ๋ณด์ž๋ฅผ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ๊ณ ๊ธ‰ ๋ ˆ์Šจ์„ ์œ„ํ•œ ์ข‹์€ ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค!

์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฐ์ •์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์ƒ๊ฐ์„ ์•„๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค :-).

@smashercosmo๊ฐ€ ๋งํ•œ ๊ฒƒ:+1:

๋‹จ์œ„ ํ…Œ์ŠคํŠธ. TDD.

@catland๊ฐ€ ๋งํ•œ ๊ฒƒ:+1:

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ด‘๋ฒ”์œ„ํ•œ ๋ฌธ์„œ์™€ ๊ฐ„๊ฒฐํ•œ ํŠœํ† ๋ฆฌ์–ผ์„ ํ†ตํ•ด ์šฐ์ˆ˜ํ•œ js ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋‹น์‹ ์˜ ๊ธฐ์ˆ ์— ๊นŠ์€ ์ธ์ƒ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

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

ํ–ฅํ›„ ๋น„๋””์˜ค์—์„œ๋Š” ํŠน์ • ๊ฐœ๋…์— ๋Œ€ํ•œ ๋ฐ˜์‘์„ ์ค„์ด๊ณ  ๋น„๋™๊ธฐ ์ž‘์—… ๋ฐ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•ด ๋” ๋งŽ์ด ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋†€๋ž๋„๋ก ์ž˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ณ„์†ํ•˜์‹ญ์‹œ์˜ค! :)

๋น„๋””์˜ค 21์—์„œ TodoApp ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋” ์ด์ƒ ํด๋ž˜์Šค์ผ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ํ•จ์ˆ˜์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ด๋Ÿฌํ•œ ๊นจ๋‹ฌ์Œ์„ ์–ป์—ˆ๋Š”์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ ์ด๊ฒƒ์ด ๊ธฐ๋Šฅ์  ๊ตฌ์„ฑ ์š”์†Œ์— ์ ํ•ฉํ•œ ํ›„๋ณด์ด๋ฉฐ ์ด๊ฒƒ์ด ์–ด๋–ค ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๊นŒ?

์ด๊ฑฐ ์ •๋ง ์ข‹๋‹ค.

@smashercosmo ๋ชฉ๋ก์˜ ํ•ญ๋ชฉ 3๋„ ์•Œ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

@wpannell์ด ๋งํ•œ ๊ฒƒ! ๋‹จ์œ„ ํ…Œ์ŠคํŠธ/TDD!

๊ณ ๊ธ‰ ๋ฌธ์„œ์—์„œ ๋‹ค๋ฃจ๋Š” ์ฃผ์ œ์— ๋Œ€ํ•œ ๋น„๋””์˜ค๋„ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ๊ด€๋ จํ•˜์—ฌ ๊ตฌ์ฒด์ ์œผ๋กœ ๋ฌด์—‡์— ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๊นŒ?
5, 11, 12๊ณผ์—์„œ๋Š” ๊ฐ์†๊ธฐ๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

...๊ทธ๊ฑด ์ข‹์€ ์งˆ๋ฌธ์ด์•ผ. ๋ชจ์นด ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ฉด ๊ณผ์ •์ด ๋งŽ์ด ๋‹ฌ๋ผ์ง€๋‚˜์š”?

์„ค๋งˆ. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ผ๋ จ์˜ ๊ณ ๊ธ‰ ์ˆ˜์—…์„ ์œ„ํ•œ ์ข‹์€ ์ฃผ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์œ„ ํ…Œ์ŠคํŒ… ๋ฆฌ๋“€์„œ, ์•ก์…˜ ์ƒ์„ฑ๊ธฐ, ์ปดํฌ๋„ŒํŠธ ๋“ฑ

์ฒซ์งธ, ํ›Œ๋ฅญํ•œ ๋น„๋””์˜ค. ์ด๋ฏธ redux๋ฅผ ์ดํ•ดํ–ˆ์ง€๋งŒ ์ƒ์พŒํ–ˆ์Šต๋‹ˆ๋‹ค.
๋” ๊ณ ๊ธ‰ ๋น„๋””์˜ค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ ๋น„๋™๊ธฐ ์ž‘์—…/๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹จ์œ„ ํ…Œ์ŠคํŠธ์— ์‹ค์ œ๋กœ ์ ์šฉ ๋ฒ”์œ„๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๊ฐ์†๊ธฐ ๊ธฐ๋Šฅ์„ ํ˜ธ์ถœํ•˜๊ณ  ์ด์— ๋Œ€ํ•ด ์ฃผ์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ, ๋ชจ์นด ํ…Œ์ŠคํŠธ์—์„œ expect ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ๋ณ„ ๋‹ค๋ฅธ ๊ฒƒ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. :์—„์ง€์†๊ฐ€๋ฝ:

๊ณ ๋ง™๊ฒŒ๋„ ๋ชจ๋“  ๊ฒƒ์ด ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค!

๊ฐœ์ฒด ID ํ•ด์‹œ์˜ ๋ถˆ๋ณ€์„ฑ(์˜ˆ: [post._id]: {...post} ).

API ์—”ํ„ฐํ‹ฐ ๋ฐฐ์—ด์„ ๊ฐ€์ ธ์™€์„œ ID ํ•ด์‹œ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด reduce ํ•จ์ˆ˜์— ๋„ˆ๋ฌด ๋งŽ์ด ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. normalizr ์ด ์ด ์ค‘ ์ผ๋ถ€๋ฅผ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ A ์ง€์ ์—์„œ B ์ง€์ ์œผ๋กœ ์•ˆ๋‚ดํ•˜๋Š” EggheadIO ๋น„๋””์˜ค์™€ ์œ ์‚ฌํ•œ ๋น„๋””์˜ค๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Redux ๊ธฐ๋ฐ˜์—๋งŒ ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์–ฝํ˜€ ์žˆ์Šต๋‹ˆ๋‹ค.

@raquelxmoss

๋น„๋””์˜ค 21์—์„œ TodoApp ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋” ์ด์ƒ ํด๋ž˜์Šค์ผ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ํ•จ์ˆ˜์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ด๋Ÿฌํ•œ ๊นจ๋‹ฌ์Œ์„ ์–ป์—ˆ๋Š”์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ ์ด๊ฒƒ์ด ๊ธฐ๋Šฅ์  ๊ตฌ์„ฑ ์š”์†Œ์— ์ ํ•ฉํ•œ ํ›„๋ณด์ด๋ฉฐ ์ด๊ฒƒ์ด ์–ด๋–ค ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๊นŒ?

๊ทธ๊ฒƒ์€ ์‹ค์ œ๋กœ ๋‚ด ์ชฝ์—์„œ ์•ฝ๊ฐ„์˜ ์กฐ์žกํ•œ ์ˆ˜์—… ๊ณ„ํš์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ธฐ๋Šฅ์  ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋„ˆ๋ฌด ๋Šฆ๊ฒŒ๊นŒ์ง€ ๊นจ๋‹ซ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ณด๋‹ค ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์ ์€ ๋‹จ์ˆœํ•˜๋ฏ€๋กœ ๊ฐ€๋Šฅํ•˜๋ฉด ์–ธ์ œ๋“ ์ง€ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์‹ญ์‹œ์˜ค. ๊ธฐ๋ณธ์ ์œผ๋กœ componentDidMount ๋˜๋Š” ์ƒํƒœ์™€ ๊ฐ™์€ ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๊ธฐ๋Šฅ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋„์›€์ด ๋˜๋„๋ก ์ด๋Ÿฌํ•œ ์ฝ”๋“œ ์กฐ๊ฐ์„ ์‹ค์ œ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋กœ ๋ถ„ํ• ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๊ตํ›ˆ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ์žˆ๋Š” ํ•œ ์•„๋งˆ ์ž‘๋™ํ•  ๊ฒƒ์ด์ง€๋งŒ ํด๋” ์ด๋ฆ„ ์ง€์ • ๊ทœ์น™(๊ตฌ์„ฑ ์š”์†Œ/์ปจํ…Œ์ด๋„ˆ/์ €์žฅ์†Œ/๋ฆฌ๋“€์„œ ๋“ฑ), ์–ด๋–ค ์ข…๋ฅ˜์˜ ํŒŒ์ผ์ด ์–ด๋–ค ํด๋”์— ๋“ค์–ด๊ฐ€๋Š”์ง€ ๋“ฑ์— ๋Œ€ํ•œ ๊ถŒ์žฅ ๊ทœ์น™์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ณ ๊ธ‰ ๊ฐ์†๊ธฐ ๊ตฌ์„ฑ์„ ์›ํ•ฉ๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์žฌ์‚ฌ์šฉ(๋ฆฌ๋“€์„œ ๋˜๋Š” ์—ฌ๋Ÿฌ ๋ฆฌ๋“€์„œ, ์ผ๋ จ์˜ ์ž‘์—…, ์ž‘์—… ์ƒ์„ฑ์ž, ์ผ๋ถ€ ์„œ๋ฒ„ ์ธก API์— ์•ก์„ธ์Šค, redux ํ˜•์‹๊ณผ ๊ฐ™์€ ์—ฌ๋Ÿฌ React ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋˜์ง€๋งŒ ๋” ์‹ค์ œ ์•ฑ์— ๊ณ ์œ ํ•จ). ์—ฌ๊ธฐ์—๋Š” ๋ชจ๋“ˆ์‹ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ๊ตฌ์„ฑ๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์ „์ฒด๋ฅผ ๋ณด์•˜๋‹ค, ์•„์ฃผ ์ข‹์•„! ES6/7 ๊ตฌ๋ฌธ( Object.assign -like), React 0.14 ํ•จ์ˆ˜ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์‚ฌ์šฉ ๋ฐ ๋ถˆ๋ณ€์˜ ๊ฒƒ์„ ํ”ผํ•˜๋Š” ๊ฒƒ์— ๊ฐ์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ถŒ์žฅ๋˜๋Š” ์ฝ”๋“œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋น„๋””์˜ค์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ES6/7 ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? (๊ทธ ๋ฐฉํ–ฅ์œผ๋กœ PR์„ ํ™˜์˜ํ•ฉ๋‹ˆ๊นŒ?)

๋‹จ์œ„ ํ…Œ์ŠคํŠธ, API ๋ฏธ๋“ค์›จ์–ด ์ƒ์„ฑ, Redux๋กœ OAuth/์ผ๋ถ€ ์œ ํ˜•์˜ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ˆ˜ํ–‰, redux์—์„œ Immutable ์‚ฌ์šฉ(์„ค์ • ๋ฐฉ๋ฒ•, ๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋“ฑ)

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

@gaearon ์˜ˆ์‹œ ์˜์ƒ์—์„œ ์•ก์…˜์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ํ‘œ์ค€์ ์ธ { type: string, payload: Object } ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์ž‘์—… ๊ฐœ์ฒด ์ž์ฒด์— ๋ฐฐ์น˜๋˜๋Š” ์นด์šดํ„ฐ ๋ชฉ๋ก ์˜ˆ์ œ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. { type: string, index: number } . ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์•ˆํ‹ฐ ํŒจํ„ด์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

์˜ˆ์ œ ๋น„๋””์˜ค์˜ ์ž‘์—…์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ํ‘œ์ค€ { type: string, payload: Object }์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์ž‘์—… ๊ฐœ์ฒด ์ž์ฒด์— ๋ฐฐ์น˜๋˜๋Š” ์นด์šดํ„ฐ ๋ชฉ๋ก ์˜ˆ์ œ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. { ์œ ํ˜•: ๋ฌธ์ž์—ด, ์ƒ‰์ธ: ์ˆซ์ž }. ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์•ˆํ‹ฐ ํŒจํ„ด์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

์–ด๋–ค ์‹์œผ๋กœ๋“  ์•ˆํ‹ฐ ํŒจํ„ด์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์•ก์…˜ ์˜ค๋ธŒ์ ํŠธ์ž…๋‹ˆ๋‹ค. FSA ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ _์ปจ๋ฒค์…˜_์ž…๋‹ˆ๋‹ค. Redux ์ž์ฒด์˜ ์–ด๋–ค ๊ฒƒ๋„ ์ด ๊ทœ์น™์˜ ์ด์ ์— ์˜์กดํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ ์‹œํ–‰ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์€ ์›๋ž˜ Flux ๋ฌธ์„œ์—์„œ payload , source ์— ๋Œ€ํ•ด ์˜จ๊ฐ– ๋งˆ๋ฒ• ๊ฐ™์€ ๊ฒƒ์„ ์ƒ๊ฐํ•˜๊ณค ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์ด ์กด์žฌํ•˜๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ณ  ๊ทธ๊ฒƒ๋“ค์ด ํ•„์š”ํ•œ์ง€ ์—ฌ๋ถ€๋ฅผ ์‹ ์ค‘ํ•˜๊ฒŒ ํ‰๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ๋งน๋ชฉ์ ์œผ๋กœ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๊ทธ๋“ค์€ Flux๊ฐ€ ๋ณต์žกํ•˜๊ณ  ์žฅํ™ฉํ•˜๋‹ค๊ณ  ๋ถˆํ‰ํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ๋งŽ์€ ๊ฒฝ์šฐ ์žฅํ™ฉํ•œ(ํ•„์ˆ˜๋Š” ์•„๋‹Œ) ๋ถ€๋ถ„ ์ž์ฒด๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

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

@gaearon ์ข‹์Šต๋‹ˆ๋‹ค . ๋‹จ์ˆœํ•œ ๋น„์ •ํ˜• ์ ‘๊ทผ ๋ฐฉ์‹์— ์ต์ˆ™ํ•ด์ง„ ์‚ฌ๋žŒ๋“ค์ด ๊ทœ์น™์„ ์ ์šฉํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ๋” ํฐ ์•ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

@sompylasar

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

๋˜ํ•œ FSA๋ฅผ ๋”ฐ๋ฅด์ง€ ์•Š๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๊ตฌ์กฐํ™”๋˜์ง€ ์•Š์€ ๊ฒƒ์€ ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค. { type: 'STUFF', id: 1 } ๋Š” ๋ณธ์งˆ์ ์œผ๋กœ { type: 'STUFF', payload: { id: 1 } } ๋ณด๋‹ค ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ทจํ–ฅ๊ณผ (๋•Œ๋กœ๋Š”) ๋„๊ตฌ ๊ทœ์น™์˜ ๋ฌธ์ œ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ž‘์—… ๊ฐœ์ฒด๋ฅผ payload ์ ๊ฒŒ ์œ ์ง€ํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ž‘์—…ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง€๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๊ณง ์—๊ทธํ—ค๋“œ์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ redux ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๊ฐ•์˜๊ฐ€ ๋‚˜์˜ฌ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค ๐Ÿ˜„

Dan์ด ์ฒซ ๋ฒˆ์งธ ํฌ๋ž™์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋™์•ˆ Redux ์ˆ˜์—…์„ ๋ณด๋ฅ˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋‹ค๋ฆด๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

"Idiomatic Redux๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ"๋Š” ํ›Œ๋ฅญํ•œ ๊ณ ๊ธ‰ ๊ณผ์ •์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค ๐Ÿ‘

@joelhooks ๋‘˜ ๋‹ค ๋†€๋ž์Šต๋‹ˆ๋‹ค!

jsbin์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  webpack๊ณผ ํ•ซ ๋ฆฌ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ํ˜„์‹ค ์„ธ๊ณ„๋กœ ๊ฐ€์ ธ ๊ฐ€๋ผ. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด redux์—๋งŒ ๊ตญํ•œ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๊ทธ๊ฒƒ์ด ์ž˜ ๋งž์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๋‹น์‹ ์ด ์ด๊ฒƒ์„ ๊ฐ€๋ฅด์น  ์ ์ž„์ž์ž…๋‹ˆ๋‹ค :)

@kevinrenskers์ด ๋น„๋””์˜ค ์‹œ๋ฆฌ์ฆˆ ์•„๋‹ˆ์ง€๋งŒ, ๋‹น์‹ ์ด ๋ญ”๊ฐ€๋ฅผ ํ•ด๋ถ€ ๊ฐ™์€ ๋Š๋‚Œ ๊ฒฝ์šฐ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค ๋ช‡ ๊ฐ€์ง€ ์ฐธ์กฐ ํ•  ์ˆ˜์žˆ๋Š” ์ •๋ง ์ข‹์€ ์˜ˆ boilerplates๊ฐ€!

Dan์˜ ์˜ˆ์ œ์™€ Webpack ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ์š”์ฒญํ•˜์‹  ๋ถ„๋“ค์ž…๋‹ˆ๋‹ค.

https://github.com/urbanvikingr/todo๋ฅผ ํ™•์ธ

๋‚˜๋Š” ๋น„๋””์˜ค์—์„œ Dan์˜ ์ฝ”๋“œ์™€ ์ผ์น˜ํ•˜๋„๋ก Redux๋ฅผ React ๋ฌธ์„œ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ๋กœ ์•ฝ์†ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‹ค์Œ 2์ฃผ ์•ˆ์— ์™„๋ฃŒ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค - ๋‚˜์˜ Holiday ํ”„๋กœ์ ํŠธ :) - ๊ณ„์† ์ง€์ผœ๋ด ์ฃผ์‹ญ์‹œ์˜ค.

Egghead.io ๋น„๋””์˜ค์— ๋Œ€ํ•œ ๋‚˜์˜ ์œ„์‹œ๋ฆฌ์ŠคํŠธ:
Jasmine์„ ์‚ฌ์šฉํ•œ ์•ก์…˜/๋ฆฌ๋“€์„œ ํ…Œ์ŠคํŠธ
๋ฏธ๋“ค์›จ์–ด์— ๋Œ€ํ•œ ์‹ฌ์ธต ๋ถ„์„(thunk/promise)

์Šคํฌ๋ฆฐ์บ์ŠคํŠธ๋Š” Redux์— ๋Œ€ํ•œ ๋งค์šฐ ์œ ์šฉํ•œ ์†Œ๊ฐœ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋“ฃ๊ณ  ์‹ถ์€ ๊ฒƒ์€ ๋ผ์šฐํŒ… ๋ฐ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” Redux ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

@grigio ๋ผ์šฐํŒ…์— ๋Œ€ํ•œ https://github.com/rackt/redux/issues/1145 ํ† ๋ก ์— ๊ด€์‹ฌ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@urbanvikingr ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, ๊ตฌ๋…ํ–ˆ์Šต๋‹ˆ๋‹ค. ํˆฌํ‘œ๊ฐ€ ์ข…๋ฃŒ๋œ ๊ฒƒ ๊ฐ™์ง€๋งŒ #1168์— ํˆฌํ‘œํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ˆ˜์—…์€ ์‹ค์ œ๋กœ ๊ฝค ์ข‹์€๋ฐ "๊ฐ€๊ฒŒ"๋ผ๊ณ  ํ•˜๋ฉด "ํ•˜์ฐฎ์€ ์ผ"์ฒ˜๋Ÿผ ๋“ค๋ฆฐ๋‹ค๋Š” ์ ์ด ์ฃผ์˜๋ฅผ ์‚ฐ๋งŒํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๊ฒƒ์„ ๋ˆˆ์น˜์ฑ„๊ณ  ์ฃผ์˜๋ฅผ ๋ถ„์‚ฐ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๊ทธ๊ฒƒ์„ ์ œ๊ธฐํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ์ •์น˜์ ์œผ๋กœ ์˜ณ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜ˆ, ๋‚˜๋Š” _๊ทธ_ ์‚ฌ๋žŒ์ด ๋˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด :)

๋‚˜๋Š” ๊ฒฐ๊ตญ ์˜์–ด๋ฅผ ๋” ์ž˜ํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š” ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์„ ์ž…๋‹ˆ๋‹ค ;-)

@gaearon Redux์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ •๋ง ์ž˜ ํ•˜์…จ์Šต๋‹ˆ๋‹ค. ๊ท€ํ•˜์™€ ๊ท€ํ•˜์˜ ์˜คํ”ˆ ์†Œ์Šค ์„ฑ๊ณผ์— ๊ฒฝ์˜๋ฅผ ํ‘œํ•ฉ๋‹ˆ๋‹ค.

๋†€๋ผ์šด ์ˆ˜์—… ์„ธํŠธ. ํŠนํžˆ "์†Œ์Šค ์ฝ๊ธฐ" ๋ฐฉ์‹์œผ๋กœ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ฐ ํ•ต์‹ฌ Redux ๊ธฐ๋Šฅ์„ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹์ด ๋งˆ์Œ์— ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ํŠœํ† ๋ฆฌ์–ผ๊ณผ ๋ชจ๋“  ๋ฌธ์„œ๊ฐ€ Redux์— ๋Œ€ํ•ด ์–ผ๋งˆ๋‚˜ ๋ช…ํ™•ํ•œ์ง€ ๊ฐ๋™ํ•œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์„ ๋‘ ๋ฒˆ์งธ๋กœ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ 2๋…„ ๊ฐ„์˜ ํ”„๋ก ํŠธ์—”๋“œ ๋ฐœ์ „์„ ๋”ฐ๋ผ์žก๋Š” ์‚ฌ๋žŒ์œผ๋กœ์„œ ๊ฐœ๋…์€ ๋‚ด ๋งˆ์Œ์„ ๊ฐ์‹ธ๊ธฐ๊ฐ€ ์–ด๋ ค์› ์ง€๋งŒ ๋ฌธ์„œ๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๋ฐ ๋†€๋ผ์šธ ์ •๋„๋กœ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ณ„์† ํ•ด ์ฃผ์„ธ์š”. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

(๋˜ํ•œ @jugimaster์˜ ๋ง์„ ๋“ฃ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๋‹น์‹ ์˜ ์–ต์–‘์— ์ฃผ์˜๋ฅผ ์‚ฐ๋งŒํ•˜๊ฒŒ ํ•˜๊ณ  "๋„ˆ๋ฌด ์ •์น˜์ ์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด

@ianstormtailor
๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ , ๊ทธ๊ฒƒ์€ ์•…์„ผํŠธ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค :)

๋‚˜๋„ "์‹ ๊ฒฝ์“ฐ์ง€" ์•Š์•˜์ง€๋งŒ, ํ™•์‹คํžˆ ์ฃผ์˜๊ฐ€ ์‚ฐ๋งŒํ•ด์กŒ์Šต๋‹ˆ๋‹ค!

ํ•˜์ง€๋งŒ ํ•œํŽธ์œผ๋กœ๋Š” 6๊ฐœ ๊ตญ์–ด๋ฅผ ๊ณต๋ถ€ํ•œ ์‚ฌ๋žŒ์œผ๋กœ์„œ ํ•ญ์ƒ ์–ธ์–ด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งํ•˜๋Š” ๊ฒƒ์„ _ํ•ด์™”์Šต๋‹ˆ๋‹ค_. ๊ทธ๋Ÿฐ ์ ์—์„œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋‚ด ์‹ค์ˆ˜๋ฅผ ์ง€์ ํ•ด์ค˜์„œ ๊ฐœ์ธ์ ์œผ๋กœ ๊ณ ๋ง™๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @gaearon ๋‹˜

๋‹น์‹ ์˜ ์ฝ”์Šค๋ฅผ ์ ˆ๋Œ€์ ์œผ๋กœ ์ข‹์•„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž˜ ํ–ˆ์–ด! ๋งค์šฐ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ Egghead ๊ณผ์ •์— ์„ธ ๊ฐ€์ง€ Redux ํ…Œ์ŠคํŠธ ๋น„๋””์˜ค ์ˆ˜์—…์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
https://egghead.io/series/react-testing-cookbook

๋‚ด ํฌ๋ง์€ ๊ทธ๋“ค์ด ๋‹น์‹ ์ด ํ•œ ๋ชจ๋“  ๋†€๋ผ์šด ์ผ์— ๋Œ€ํ•ด ์นญ์ฐฌ์„ ํ•ด์ฃผ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

ํ™•์‹คํ•œ ์ฝ”์Šค!

Redux ์ง€์‹๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ˜„๋Œ€์  ๊ด€ํ–‰ ์ง€์‹์„ ์ „๋ฐ˜์ ์œผ๋กœ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค! ๊ณ„์† ์ข‹์€ ์ผ๋งŒ ํ•˜์„ธ์š” :+1: :tada:

์ด๋ด, ๋ฐฉ๊ธˆ ๋น„๋””์˜ค์— ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋งํฌ/์ฐธ์กฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด ๋ช…๋ฐฑํ•˜๊ณ  ์•„๋งˆ๋„ ์ถฉ๋ถ„ํžˆ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ์ž๋Š” ๋น„๋””์˜ค๋ฅผ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋™์˜์ƒ์˜ ์ •ํ™•ํ•œ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ์ €์žฅ์†Œ๋ฅผ ํ†ตํ•ด ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์™œ ์•ˆ ๋ ๊นŒ์š”?

๋ชจ๋“  ๊ฐ•์˜์— ๋Œ€ํ•œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ Egghead ๊ตฌ๋…์ž์—๊ฒŒ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. :-)
๋น„๋””์˜ค๋Š” ๋ฌด๋ฃŒ์ง€๋งŒ ํ”Œ๋žซํผ์€ ๋ˆ์„ ๋ฒŒ์–ด์•ผ ๋” ๋งŽ์€ ์ฝ”์Šค์— ํˆฌ์žํ•˜๊ณ , ๊ฐ•์‚ฌ์—๊ฒŒ ์žฅ๋น„๋ฅผ ๋ณด๋‚ด๊ณ , ๋น„๋””์˜ค๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๊ณ , ์›น ์‚ฌ์ดํŠธ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์ฝ”์Šค์™€ ๊ฑฐ์˜ ์ผ์น˜ํ•˜๋Š” examples/todos ํด๋”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

... ์ข‹์•„, ๊ทธ๋Ÿผ ๋‚ด๊ฐ€ ๋†“์นœ๊ฑฐ์•ผ? ๋งํฌ๋ฅผ ์ฐพ๋Š” ์ค‘...

@gaearon์ด ์‚ฌ๊ณผํ•˜๊ณ  ๋ฐฉ๊ธˆ ๋น„๋””์˜ค๋ฅผ ๋‹ค์‹œ ๋ฐฉ๋ฌธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ๋ฐ”๋กœ ๊ฑฐ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค :)... ๋™์˜์ƒ์„ ๋ณด๊ณ , ๋ฉค๋ฒ„์‹ญ์„ ๊ตฌ๋งคํ•˜๊ณ , ๋‹ค๋ฅธ ์‚ฌ๋žŒ์„ ๋ณด๊ณ ... ์‹ค์ œ๋กœ ๋กœ๊ทธ์ธํ•œ redux ๋™์˜์ƒ์œผ๋กœ ๋Œ์•„๊ฐ”์Šต๋‹ˆ๋‹ค. ๊ฑด๋ฐฐ.

๊ทธ๋Ÿฐ๋ฐ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ ์„ฑ์ ํ‘œ๊ฐ€ ์ •ํ™•ํ•˜์ง€ ์•Š๋‹ค๊ณ  ๋ถˆํ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ˆ˜์ •์„ ์œ„ํ•ด PR์„ ๋ณด๋‚ด์ฃผ์‹ญ์‹œ์˜ค: https://github.com/eggheadio/egghead-redux-transcripts

@gaearon redux๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•˜๊ณ  egghead์—์„œ redux vids๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. ๋น„๋””์˜ค๋Š” ๋‚ด๊ฐ€ redux๋ฅผ ๋ฐฐ์šฐ๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ์ •๋ง ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ๋” ๋งŽ์€ ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ๋ณด๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์•ž์œผ๋กœ redux ๋น„๋””์˜ค ๊ต์œก์— ๋Œ€ํ•œ ์ œ ์ œ์•ˆ์€ ๊ณ ๊ธ‰ ๊ตฌ์„ฑ, ๋ฆฌํŒฉํ† ๋ง์— ๋Œ€ํ•œ ์‹ฌ์ธต ๋ถ„์„ ๋ฐ ํ™•์‹คํžˆ reselect๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์–ธ์ œ ๋ฆฌํŒฉํ† ๋งํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ง๊ด€์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ redux์™€ ๋งค์šฐ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๋ฆฌํŒฉํ† ๋ง ์‹œ๊ธฐ์™€ ํ•œ ๊ฐ€์ง€ ์ผ์„ ์ž˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ํŒ์„ ์–ป๋Š” ๊ฒƒ์ด ์ •๋ง ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งŒ๋“ค๊ณ  ์žˆ๋Š” ์•ฑ์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ ์ปฌ๋ ‰์…˜์ด ์žˆ์œผ๋ฉฐ ํ…Œ์ด๋ธ”์— ๋„ฃ๊ณ  ๋ฐ์ดํ„ฐ ์ •๋ ฌ ๋ฐ ํŽ˜์ด์ง€ ๋งค๊น€๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์„ ํƒ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๋งŒ๋“ค๊ธฐ ์ž‘์—…์„ ์‚ฌ์šฉํ•  ๋•Œ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํ…Œ์ด๋ธ”์—์„œ ์ผ๋ถ€ ์ƒํƒœ๋ฅผ "์ƒ์†" ์ €์žฅํ•˜๋„๋ก ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ USERS_SORT_TABLE ์ž‘์—…๊ณผ SORT_TABLE ์ž‘์—…์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ €์žฅ์†Œ๋ณ„๋กœ ์ •๋ ฌ๋˜๋Š” ํ• ์ผ ์ €์žฅ์†Œ์— ๋Œ€ํ•œ SORT_TABLE ์ž‘์—…์„ ์›ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์†”๋ฃจ์…˜์ด DRY๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š” ํ…Œ์ด๋ธ”์„ ์ฑ„์šฐ๊ณ ์ž ํ•˜๋Š” ๋ชจ๋“  ์ƒ์ ์— ๋Œ€ํ•ด "SOMETHING"_SORT_TABLE ์ž‘์—…์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ž˜๋ชป๋œ ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๋ถ€์ž‘์šฉ์€ ์•ก์…˜์— ์ด๋ฆ„์„ ์ ‘๋‘์‚ฌ๋กœ ๋ถ™์—ฌ ๋‹ค๋ฅธ ์ €์žฅ์†Œ๋ฅผ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด ์•ก์…˜ ์ด๋ฆ„์ด ๊ฑฐ๋Œ€ํ•ด์ง€๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์˜ณ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

/* actions.js */
// ...
export const USER_MOVE_COLUMN = 'USER_MOVE_COLUMN'

export function userMoveColumn (columnIndex, moveToIndex) {
  return {
    type: USER_MOVE_COLUMN,
    columnIndex,
    moveToIndex
  }
}

export const DATA_TABLE_MOVE_COLUMN = 'DATA_TABLE_MOVE_COLUMN'
// ...

/* reducers.js */
// ...
export default function user (state=userInitialState, action) {
  switch (action.type) {
    // ...
    case USER_MOVE_COLUMN:
      return dataTable(state, assign(
        action,
        {type: DATA_TABLE_MOVE_COLUMN}
      ))
    // ...
    default:
      return state
  }
}
// ...
export default function dataTable (
  state=dataTableInitialState,
  action,
  key='dataTable')
{
  switch (action.type) {
    // ...
    case DATA_TABLE_MOVE_COLUMN:
      return {
        ...state,
        [key]: {
          ...state[key],
          columns: move(
            state[key].columns, action.columnIndex, action.moveToIndex
          )
        }
      }
    // ...
    default:
      return state
  }
}

๋”ฐ๋ผ์„œ ํ…Œ์ด๋ธ”๊ณผ "๋ชจ๋ธ" ์ €์žฅ์†Œ ์‚ฌ์ด์— ์กด์žฌํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” ์ข…์†์„ฑ์„ ์ƒ์„ฑํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ชจ๋ธ ์ €์žฅ์†Œ๋Š” ๊ฐœ์ฒด ๋ฐฐ์—ด์— ๋Œ€ํ•ด ์ปฌ๋ ‰์…˜ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•จ). ๊ทธ๋ฆฌ๊ณ  dataTable์€ "๋ถ€๋ชจ" ๋ฆฌ๋“€์„œ์˜ ์ƒํƒœ๋ฅผ ์กฐ์ž‘ํ•˜๋Š”๋ฐ, ๊ทธ๋ ‡๊ฒŒ ํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๊ฑฐ๊ธฐ์—์„œ ์„ ํƒ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์ง€๋งŒ ์ด ๊ธ€์„ ์ž‘์„ฑํ•  ๋‹น์‹œ์—๋Š” UI์— ํ‘œ์‹œ๋˜๋Š” ๋‚ด์šฉ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ํฐ ์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ํ˜„์žฌ ์ €๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ ์ค‘ ์ผ๋ถ€๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์žฌ์„ ํƒ๊ณผ ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฆฌํŒฉํ† ๋ง ๊ธฐ์ˆ ์„ ๋ฐฐ์šฐ๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ Redux ๊ณผ์ •์€ ๋‚˜๋ฅผ ์œ„ํ—˜ํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ์— ์ถฉ๋ถ„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ œ๋Œ€๋กœ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. :)

๋„ˆ๋ฌด ์žฅํ™ฉํ•˜์ง€ ์•Š๊ณ  ๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•˜๊ณ  ์ •์งํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์ €๋ฅผ ๋„์™€์ค„ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์˜ํ˜ผ์„ ์œ„ํ•ด ์ €๋Š” ์ด๋ฏธ ๋‹ค๋ฅธ Dan์˜ ๋Œ“๊ธ€์—์„œ /examples/real-world/reducers ๋ฅผ ์ฐพ์•˜์œผ๋ฉฐ ํ˜„์žฌ ์œ„์—์„œ ์„ค๋ช…ํ•œ ๋ฌธ์ œ ์ค‘ ์ผ๋ถ€๋ฅผ ์žฌ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์„ ๋•Œ ๋„์›€์„ ์ฃผ๋Š๋ผ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜์ง€ ์•Š์•˜์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :)

๋‚ด ํ”„๋กœ์ ํŠธ์— redux-devtools๋ฅผ ํ†ตํ•ฉํ•˜๋Š” ๊ฒƒ์€ ์ €์—๊ฒŒ ํฐ ๊ณ ํ†ต์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฑฐ๊ธฐ์— ๋ฌด์—‡์ด ์žˆ๊ณ  ์–ด๋–ป๊ฒŒ/์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์„ค๋ช…ํ•˜๋Š” ์—๊ทธํ—ค๋“œ ์‹œ๋ฆฌ์ฆˆ๋ฅผ ๋†’์ด ํ‰๊ฐ€ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์–ธ์ œ ๋ฌด์—‡์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š”์ง€ ์„ค๋ช…ํ•˜๋Š” PR์„ ์ฝ์—ˆ์ง€๋งŒ .. ๋„ˆ๋ฌด ๋งŽ์€ ๊ฒƒ๋“ค์ด ๋„ˆ๋ฌด ๋งŽ์•„์„œ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ–ˆ์Šต๋‹ˆ๋‹ค. hmr, transform 3, redux hot reloader๋Š” react hot reloader ๋“ฑ๋“ฑ..

์œ„์—์„œ ์„ค๋ช…ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๋กœ ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์„ ์œ„ํ•ด Redux์˜ ๋ชจ๋“  ์ƒ์šฉ๊ตฌ๋Š” ๋ฌผ๋ก  ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ž‘์—…์„ ๋Œ€๋ถ€๋ถ„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ์ฐธ์กฐ

@granteagon ์ด ์ปคํ”Œ์€ ๋ฆฌ๋“€์„œ์—์„œ ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ๋กœ

์•ก์…˜/๋ฆฌ๋“€์„œ ์ƒ์„ฑ ์œ„์— ๋ž˜ํผ ๋˜๋Š” ์ถ”์ƒํ™”๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์€ ํ•ญ์ƒ ์ง์ ‘์ ์œผ๋กœ ํ•จ๊ป˜ ๊ฒฐํ•ฉ๋  ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ, ๋‚ด ์•ฑ์—์„œ ์ง€๊ธˆ๊นŒ์ง€ ๋‚ด ์ž‘์—…์˜ _๋Œ€๋ถ€๋ถ„์˜_์—๋Š” ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ์ฒ˜๋ฆฌ ๋…ผ๋ฆฌ ๋ฉ์–ด๋ฆฌ๊ฐ€ ์žˆ์ง€๋งŒ ํŠธ๋ฆฌ์˜ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•˜๋Š” ๊ณณ์ด ๋ช‡ ๊ตฐ๋ฐ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

@gaearon @markerikson ์•ก์…˜ ํฌ๋ฆฌ์—์ดํ„ฐ์— ๋ฆฌ๋“€์„œ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹œ๊ฐ„์˜ 90%๋Š” ๊ดœ์ฐฎ๊ฑฐ๋‚˜ ์‹ฌ์ง€์–ด ์›ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ 10%๋Š” ์—ฌ์ „ํžˆ ์†์œผ๋กœ ์ฝ”๋”ฉํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ง์”€ํ•ด์ฃผ์‹  ๋ถ€๋ถ„์€ ์ƒ๊ฐํ•ด๋ณด๊ณ  ํ–ฅํ›„ ๋ฐœ์ „์„ ์œ„ํ•ด ๊ณ ๋ คํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@granteagon @gaearon

reduxr๊ณผ ์œ ์‚ฌํ•œ ๋กœ์ปฌ ์ถ”์ƒํ™”๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์— ์ถ”๊ฐ€๋œ ๊ฒฐํ•ฉ์ด ์—†๋‹ค๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ์•ก์…˜๊ณผ ๋ฆฌ๋“€์„œ ๊ฐ„์— 1:1 ๋งคํ•‘์„ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜์‹ ํ•˜๋Š” ๋‘ ๊ฐœ์˜ ๋‹ค๋ฅธ ์Šฌ๋ผ์ด์Šค์— ๋‘ ๊ฐœ์˜ ๋ฆฌ๋“€์„œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const counterReducersA = {
  // this counter increments by 1 each time
  increment: (state, action) => state + 1
}

const counterReducersB = {
  // this counter increments by 2 each time
  increment: (state, action) => state + 2
}

const counterA = reduxr(counterReducersA, 0);
const counterB = reduxr(counterReducersB, 0);

const rootReducer = combineReducers({
  counterA: counterA.reducer,
  counterB: counterB.reducer
});

store.dispatch(counterA.action.increment());  // increments both counters

๋ฌผ๋ก , ๊ฐ™์€ ์ด๋ฆ„์˜ "๋ฆฌ๋“€์„œ" ๊ธฐ๋Šฅ์ด ๋‘ ๊ฐœ ์ด์ƒ ์žˆ๋Š” ๊ฒฝ์šฐ(์ฆ‰, ๋™์ผํ•œ ์ž‘์—…์— ์‘๋‹ต), ์•”์‹œ์ ์œผ๋กœ ๋‘˜ ๋‹ค ์ž‘์—… ํŽ˜์ด๋กœ๋“œ๊ฐ€ ํŠน์ • ๋ชจ์–‘์„ "์˜ˆ์ƒ"ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์™„์ „ํžˆ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋‹๋ผ redux์— ๋‘ ๊ฐœ์˜ ๊ฐ์†๊ธฐ๊ฐ€ ๋ชจ๋‘ ๋™์ผํ•œ type ์ƒ์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜๋ ค๋ฉด --- ๋‘˜ ๋‹ค ๋™์ผํ•œ ๋™์ž‘ ๋ชจ์–‘์„ ๊ธฐ๋Œ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@gaearon ์ปคํ”Œ๋ง์ด ๋ฌด์Šจ ๋ง์ธ์ง€ ์ œ๊ฐ€ ์ž˜๋ชป ์ดํ•ด

์ฝํฌ ๊ตฌํ˜„์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์ „์— ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†๋Š” ๋น„๋™๊ธฐ ํ๋ฆ„์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์†Œ ๊ด€๋ จ์ด ์žˆ์ง€๋งŒ ๋ฌธ์„œ๊ฐ€ ๋ฏธ์นœ ๋“ฏ์ด ๋„์›€์ด ๋˜๋Š” ๋™์•ˆ ๋น„๋™๊ธฐ ํ๋ฆ„ ํŽ˜์ด์ง€์˜ ์ด ์„ค๋ช…์€ ๋Œ์ด์ผœ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์ •๋ง ์ €๋ฅผ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. "๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†์œผ๋ฉด Redux ์ €์žฅ์†Œ๋Š” ๋™๊ธฐ ๋ฐ์ดํ„ฐ ํ๋ฆ„๋งŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค."

@battaile : ๊ทธ๊ฒŒ ์‚ฌ์‹ค์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค :) ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†์œผ๋ฉด ๋น„๋™๊ธฐ store.dispatch ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ž‘์—…์€ ๊ฐ์†๊ธฐ ๊ธฐ๋Šฅ์œผ๋กœ ๋ฐ”๋กœ ์ด๋™ํ•˜๊ณ  Go๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๊ณ  $200๋ฅผ ์ˆ˜์ง‘ํ•˜์ง€ ์•Š์œผ๋ฉฐ AJAX ํ˜ธ์ถœ์„ ์œ„ํ•ด ๋„์ค‘์— ์ค‘์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์Šคํ† ์–ด ์ธํ•ธ์„œ๋Š” dispatch ์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ž์‹ ์˜ ๋ฒ„์ „์œผ๋กœ ๋งˆ๋ฌด๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ applyMiddleware ๋Š” ์‹ค์ œ ์ƒ์ ์˜ dispatch ๊ธฐ๋Šฅ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— "๋ฏธ๋“ค์›จ์–ด ํŒŒ์ดํ”„๋ผ์ธ"์˜ ์ถ”์ƒํ™”๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. . ์ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ‘œ์ค€ Redux ํ๋ฆ„ _๋‚ด๋ถ€์—์„œ_ ์›ํ•˜๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํ—ˆ์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฏธ๋“ค์›จ์–ด ์—†์ด๋„ ์—ฌ์ „ํžˆ ์™„์ „ํžˆ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ์‹ค์ œ๋กœ Redux์™€ ๊ด€๋ จ๋œ ๊ฒƒ๊ณผ ์™„์ „ํžˆ ๋ณ„๊ฐœ๋กœ ๋ฐœ์ƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค :)

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๊ฑฐ์ง“์ด๋ผ๊ณ  ๋งํ•˜์ง€ ์•Š์•˜๋‹ค, ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋‚˜๋ฅผ ๊ถค๋„์—์„œ ๋ฒ—์–ด๋‚ฌ๋‹ค๊ณ  ๋งํ–ˆ๋‹ค :)

๋‚˜๋Š” ๋‹จ์ง€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ผ์„ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

const mapDispatchToProps = (dispatch) => ({
  onclick(searchTerm) {
    dispatch(actions.requestOrders(searchTerm));

    return fetch('http://localhost:49984/Order/Search?search=' + searchTerm)
      .then(response => response.json()).then(response => {
        dispatch(actions.receiveOrders(searchTerm, response));
      })
      .catch((err) => {
        dispatch(actions.receiveOrdersError('An error occurred during search: ' + err.message));
      });
  },
});

๋‚˜๋Š” ์ด๊ฒƒ์ด ์‰ฝ๊ฒŒ ์ถ”์•…ํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๊ฐœ๋…์ ์œผ๋กœ๋Š” ๋ณด๋Š” ๊ฒƒ์ด ์œ ์šฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด ์ ์–ด๋„ ๋‚ด ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋žฌ๋‹ค.

"๋ฏธ๋“ค์›จ์–ด ์—†์ด Redux ์Šคํ† ์–ด๋Š” ๋™๊ธฐ์‹ ๋ฐ์ดํ„ฐ ํ๋ฆ„๋งŒ ์ง€์›ํ•œ๋‹ค"๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์˜คํ•ด์˜ ์†Œ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์ ์œผ๋กœ "๋‚ด๋ถ€"์™€ "์™ธ๋ถ€"๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ทธ ๋ง์ด ์‚ฌ์‹ค์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋น„๋™๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ์‚ฌ๋žŒ๋“ค์ด ๋ฏฟ๊ฒŒ ํ•˜๋Š” ๊ฒฝ์šฐ, ์•„๋งˆ๋„ ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ๋‹ค์‹œ ๋งํ•˜๊ฑฐ๋‚˜ ์ž์„ธํžˆ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ.

์˜ˆ, ์ฐจ์ด์ ์€ ๋น„๋™๊ธฐ ๋™์ž‘์ด ๊ธฐ์ˆ ์ ์œผ๋กœ dispatch "๋‚ด๋ถ€"๋ณด๋‹ค๋Š” ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜์ค€์—์„œ ๋” ๋งŽ์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์†Œํ•œ ์ฐจ์ด์ง€๋งŒ ์œ ํšจํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ์ง„์ˆ ์ด ๊ธฐ์ˆ ์ ์œผ๋กœ ์˜ณ์ง€ ์•Š๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋Š” ์‚ฌ๋žŒ์€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@markerikson ๋‚ด๋ถ€์™€ ์™ธ๋ถ€์˜ ๊ตฌ๋ถ„์ด ์ค‘์š”ํ•œ ๊ตฌ์ฒด์ ์ธ ์˜ˆ๊ฐ€ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ์˜ˆ๋Š” ๋น„๋™๊ธฐ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋””์ŠคํŒจ์น˜๋œ ์ฝํฌ(๋˜๋Š” ์•ฝ์† ๋“ฑ)๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ธฐ _before_ ์ฒด์ธ์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ _๋ฌด์—‡์„_ ํ•  ๊ฒƒ์ธ์ง€ _๋ฌด์—‡์„__ ํ™•์‹ ํ•  ์ˆ˜ ์—†์ง€๋งŒ, ๊ทธ๋Ÿฐ ๊ฒƒ์„ ์›ํ•˜๋Š” ๊ฒƒ์ด ์‹คํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์Œ... ๊ตฌ์ฒด์ ์œผ๋กœ "๊ตฌ์ฒด์ ์ธ" ์˜ˆ์— ๋Œ€ํ•ด์„œ๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์œผ๋กœ "outside"์™€ "insie"์˜ ๊ตฌ๋ถ„์€ dispatch ๋ฅผ ์ฒ˜์Œ์œผ๋กœ ํ˜ธ์ถœํ•˜๊ธฐ _์ „_ ๋˜๋Š” _ํ›„_์— ๋ฐœ์ƒํ•˜๋Š”์ง€์˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. "outside" ๋ฐ "before"์ธ ๊ฒฝ์šฐ ๋ชจ๋“  ๋น„๋™๊ธฐ์„ฑ๊ณผ ๋…ผ๋ฆฌ๊ฐ€ React, Angular ๋˜๋Š” ๋‹ค๋ฅธ ๋ฌด์—‡์ด๋“  ๊ด€๊ณ„์—†์ด ๋ทฐ ๋ ˆ์ด์–ด์— ๋” ๋งŽ์ด ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. "๋‚ด๋ถ€" ๋ฐ "์ดํ›„"์ธ ๊ฒฝ์šฐ ๋น„๋™๊ธฐ์„ฑ๊ณผ ๋…ผ๋ฆฌ๋Š” ์ €์žฅ์†Œ ์ˆ˜์ค€์— ์žˆ์œผ๋ฉฐ ๋ณด๊ธฐ ๊ณ„์ธต์— ์—ฐ๊ฒฐ๋˜์ง€ _์•Š์Šต๋‹ˆ๋‹ค_.

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ์˜ค๋Š˜ ์ผ์ฐ Reddit ํ† ๋ก ์—์„œ ๋งŒ๋“ค๋ ค๊ณ  ํ–ˆ๋˜ ์š”์ ์ž…๋‹ˆ๋‹ค: https://www.reddit.com/r/reactjs/comments/4spbip/has_anyone_inserted_a_controllerpresenter_layer/ .

"์–ด๋–ค ์ž‘์—…์„ ๋ฐœ์†กํ•˜๊ณ  ์–ธ์ œ ๋ฐœ์†กํ•ฉ๋‹ˆ๊นŒ?"์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ ์ ˆ๋ฐ˜์€ "์ด๋Ÿฌํ•œ ์ž‘์—…์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋‚ด ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๊นŒ?"์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ์˜ ํ•ต์‹ฌ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์•ก์…˜ ๊ด€๋ฆฌ๊ฐ€ ์ฝํฌ(thunks)์™€ ๋ฌด์šฉ๋‹ด(sagas) ๋“ฑ์— ์žˆ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ React ๊ตฌ์„ฑ ์š”์†Œ, Angular ์ปจํŠธ๋กค๋Ÿฌ, jQuery ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ, Vue ๊ตฌ์„ฑ ์š”์†Œ ์ธ์Šคํ„ด์Šค ๋˜๋Š” ๋‹ค๋ฅธ ๊ฒƒ์— ์˜ํ•ด ์‹œ์ž‘๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” ์‹ค์ œ๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•ต์‹ฌ ๋กœ์ง์€ UI ๋ ˆ์ด์–ด ์™ธ๋ถ€์— ์žˆ์œผ๋ฉฐ UI ๋ ˆ์ด์–ด๋Š” ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์Šคํ† ์–ด ๋ฐ–์œผ๋กœ ๊ฐ€์ ธ์™€ ํ‘œ์‹œํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์•ฑ ๋กœ์ง ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋ฐ”๊พธ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ "๋‚ด๋ถ€" ๋Œ€ "์™ธ๋ถ€"์˜ ์งˆ๋ฌธ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋…ผ๋ฆฌ๊ฐ€ ์•ฑ ์ˆ˜์ค€์— ์žˆ๋Š”์ง€ UI ์ˆ˜์ค€์— ์žˆ๋Š”์ง€๋ฅผ ๊ฐœ๋…์ ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

@markerikson ์ด ์งˆ๋ฌธ์— ๋Œ€ํ•ด ํ•จ๊ป˜

์ฐธ๊ณ : ํŽธ์˜๋ฅผ ์œ„ํ•ด thunk ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ๋กœ redux-thunk์ด๋“  redux-promise์ด๋“  ๊ฐ„์— ๋น„๋™๊ธฐ์— ๋Œ€ํ•œ ์ž„์˜์˜ ๋ฏธ๋“ค์›จ์–ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

UI ๋ ˆ์ด์–ด๋Š” ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์„ ํ•ธ๋“ค๋Ÿฌ์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด UI๊ฐ€ _some_ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์กฐ์ž‘๋ฉ๋‹ˆ๋‹ค. ์ข…์ข… ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ด๋Ÿฌํ•œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ props๋กœ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐ”์ธ๋”ฉ๋œ ์ž‘์—… ์ƒ์„ฑ์ž์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. UI๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. --- ๊ทธ๋ƒฅ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

"ํ•ธ๋“ค๋Ÿฌ"๊ฐ€ (๋ฏธ๋“ค์›จ์–ด์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋ ) ํ•จ์ˆ˜๋ฅผ ๋””์ŠคํŒจ์น˜ํ•˜๋Š”์ง€ ๋˜๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ์‹คํ–‰ํ•˜๊ณ  _then_์ด ์ผ๋ฐ˜ ์ž‘์—…์„ ๋””์ŠคํŒจ์น˜ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” UI ๋ ˆ์ด์–ด์— ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. --- UI๋Š” ์™„์ „ํžˆ ๋ถˆ๊ฐ€์ง€๋ก ์ ์ž…๋‹ˆ๋‹ค. _๊ฐ€๋Šฅ_ ๋ถˆ๊ฐ€์ง€๋ก ์ ์ผ ์ˆ˜ ์žˆ์Œ)

์ฝํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด "์•ฑ"์˜ ๋งŽ์€ ๋ถ€๋ถ„์ด ์ด๋Ÿฌํ•œ "์ฒ˜๋ฆฌ๊ธฐ"์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ react/redux ์•ฑ์—์„œ ์ด๋Ÿฌํ•œ "ํ•ธ๋“ค๋Ÿฌ"๋Š” ์ข…์ข… ์ผ์ข…์˜ ์•ก์…˜ ์ƒ์„ฑ์ž์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๋น„๋™๊ธฐ ํ•ญ๋ชฉ์„ ์ฝํฌ๋กœ ์ž‘์„ฑํ•˜๊ณ  ๋ฐœ์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ๋ชจ๋“  ๋น„๋™๊ธฐ ํ•ญ๋ชฉ์„ dispatch ์ธ์ˆ˜๋กœ ํ—ˆ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ด€์ ์—์„œ ๋ณผ ๋•Œ someHandler(dispatch) OR dispatch(someHandler()) ๋˜๋Š” ์ƒ์œ„์—์„œ ์ƒ์†๋œ ๋ฐ”์ธ๋”ฉ๋œ ์ž‘์—… ์ž‘์„ฑ์ž์˜ ๊ฒฝ์šฐ ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ someHandler() ์ž…๋‹ˆ๋‹ค. UI ๋ ˆ์ด์–ด์™€ ์ด ์ฐจ์ด๋ฅผ ์™„์ „ํžˆ ๊ฐ€๋ฆฌ๋Š” bindActionCreators ๋ฒ„์ „์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ก์…˜ ์ œ์ž‘์ž๋กœ ์ž‘์„ฑ๋œ react/redux ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ œ๊ณตํ•˜๋ฉด UI ๊ณ„์ธต์„ _๊ทผ๋ณธ์ ์œผ๋กœ_ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ ๋„ redux-thunk๋ฅผ ์™„์ „ํžˆ ๊ต์ฒดํ•˜๊ณ  ๋น„ ๋ฏธ๋“ค์›จ์–ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ฐธ๊ณ : getState ์„ ์ฃผ์ž…ํ•˜๋Š” ์œ„์น˜/๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ  ์žˆ์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ๋Š” ์‚ฌ์†Œํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด๋ผ๊ณ  _๋ฏฟ์Šต๋‹ˆ๋‹ค_).

๋”ฐ๋ผ์„œ '๋‚ด๋ถ€'์™€ '์™ธ๋ถ€'์˜ ๊ตฌ๋ถ„์ด '์•ฑ ์ˆ˜์ค€' ๋˜๋Š” 'UI ์ˆ˜์ค€'์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ๋ฐ›์•„๋“ค์ด๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ† ๋ก ์— ๊ฐ์‚ฌ๋“œ๋ฆฌ๋ฉฐ ๋ถ€์ •์ ์ธ ์˜๊ฒฌ์ด ๋‚˜์˜ค์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด ์ฝ”์Šค๋Š” ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ์ฝ”์Šค์— ๋Œ€ํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋…ธํŠธ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋กœ ์˜๊ฒฌ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ์ด๊ฒƒ์„ ๋‹ซ์Šต๋‹ˆ๋‹ค: https://github.com/tayiorbeii/egghead.io_redux_course_notes

๊ทธ๋ฆฌ๊ณ  ๋Œ„์ด ๋ญ‰์นœ ๋‹ค์Œ ์‹œ๋ฆฌ์ฆˆ๋„ ๊ผญ ํ™•์ธํ•ด๋ณด์„ธ์š”! https://egghead.io/courses/building-react-applications-with-idiomatic-redux

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰