Redux: ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ redux๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•

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

๊ฐ€๋Šฅํ•ฉ๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ๋‚ด๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

let initialState = immutable.fromJS({some_store: "some initial data"});
const redux = createRedux(stores, initialState);
...
export function some_store(state, action) {
    // state is undefined here
}
help wanted question

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

๋ฟก๋ฟก

Redux์™€ ํ•จ๊ป˜ Immutable ์‚ฌ์šฉ์˜ ์žฅ์  :

  • ์‹ค์ˆ˜๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋Œ€ํ˜• ์–ด๋ ˆ์ด ๋ฐ ๊ฐ์ฒด๋กœ ๋” ๋น ๋ฅธ ์„ฑ๋Šฅ๊ณผ ๋” ๋‚˜์€ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„

Redux์™€ ํ•จ๊ป˜ Immutable ์‚ฌ์šฉ์˜ ๋‹จ์  :

  • ํŒ€์„ ์œ„ํ•ด ๋ฐฐ์šธ ์ˆ˜์žˆ๋Š” ์ƒˆ๋กœ์šด API
  • ๋ฒˆ๋“ค ํฌ๊ธฐ ์ฆ๊ฐ€
  • ๋””๋ฒ„๊ทธ๊ฐ€ ์•ฝ๊ฐ„ ๊นŒ๋‹ค ๋กญ์Šต๋‹ˆ๋‹ค.

ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„๋Š” ๋‹น์‹ ์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค!

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

๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฑด ์ด๋Ÿฐ ๊ฒƒ ๊ฐ™์•„์š”

// stores/some-store.js
import Immutable from 'immutable'

const { Map, List, fromJS } = Immutable
const initialState = Map({
  foo: 'bar',
  fooList: List()
})

export function someStore (state = initialState, action) {
  if (action.type === 'FOO') {
    return state.set('foo', fromJS(action.foo))
  }
  if (action.type === 'FOO_LIST') {
    return state.set('fooList', fromJS(action.fooList))
  }

  return state
}

// stores/index.js
export { default as someStore } from './some-store'

// application.js
import * as stores from './stores'

const redux = createRedux(stores)

@emmenko๊ฐ€ ๋ณด์—ฌ์ค€ ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ธฐ๋ณธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์ ์ด ์ž์ฒด ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์ •์˜ํ•˜๋„๋กํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

initialState ์ธ์ˆ˜๋Š” ์„œ๋ฒ„ ๋˜๋Š” localStorage์—์„œ ์ƒํƒœ๋ฅผ ๋‹ค์‹œ ์ˆ˜ํ™”ํ•˜๋Š” ๋ฐ๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ( @acdlite , ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ๋ฌธ์„œ์—์„œ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

์ฆ‰, ์‹œ๋„ํ•œ ๊ฒƒ์ด ์ž‘๋™ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ์กฐ์‚ฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์•„๋‹ˆ์š”, ์‹œ๋„ํ•œ ๋‚ด์šฉ์ด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋งค์žฅ์˜ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๊ณณ์—์„œ ๋งŒ๋“ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ํ•˜์ง€ ๋ง์•„์•ผ ํ•  ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋ชจ๋“  ๋งค์žฅ์˜ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๊ณณ์—์„œ ๋งŒ๋“ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ํ•˜์ง€ ๋ง์•„์•ผ ํ•  ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๊ทธ๊ฒƒ์€ ๋‹น์‹ ์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์—ด์–ด ๋‘๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฃผ์— ๋‹ค์‹œ ๋ฐฉ๋ฌธํ•˜์—ฌ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ํ•จ๊ป˜ composeStores ์ผ๋ฐ˜ JS ๊ฐ์ฒด๊ฐ€ ๋ฃจํŠธ ์ƒํƒœ๋ฅผ ๊ฐ€์ •ํ•˜์—ฌ,์™€ ํ•จ๊ป˜ ์†์„ฑ์— ์•ก์„ธ์Šคํ•˜๊ณ  ์žˆ์Œ state[key] ์‹คํŒจํ•˜๋Š” Immutable.Map . ์ผ๋ฐ˜ JS ์†์„ฑ์„ ํ†ตํ•ด ํ•„๋“œ์— ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Immutable.Record ์™€ ํ•จ๊ป˜ ์ž‘๋™ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ‰๋ฒ”ํ•œ ๋ฌผ์ฒด๋ฅผ ๊ฐ€์ •ํ•˜๋Š” ๋‹ค๋ฅธ ๊ณณ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค. ๋Œ€๋‹จํ•œ ์บ์น˜์ž…๋‹ˆ๋‹ค! ์„ค๋ช… ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ด๋ฉ๋‹ˆ๋‹ค.

์ปค๋„ฅํ„ฐ ์‚ฌ์šฉ๋„ isPlainObject(Immutable.Record) === false ๊ฐ™์€ ์ด์œ ๋กœ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

@pierregm ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๋งž์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ ์†Œํ’ˆ์— ๋ ˆ์ฝ”๋“œ ์†์„ฑ์„ ๋ถ„์‚ฐํ•˜๋ฉด ์–ด์จŒ๋“  ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. select={state => state.get('something').toJS()} ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ท€ํ•˜์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์ž‘๋™ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

// store
const initialState = Immutable.fromJS({}).toOrderedMap();

export default function streamStore(state = initialState, action) {
  switch (action.type) {

    case actionTypes.FETCH_STREAM_DONE:
      var streamMap = {};

      for (var i in action.stream_data) {
        var item = action.stream_data[i];
        streamMap[item.id] = item;
      }
      return state.merge(Immutable.fromJS(streamMap).toOrderedMap());

    default:
      return state
  }
};

// select
function select(state) {
  return {stream: state.stream.toList()}
}

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

์˜ค ์™€์ด์Šค

Reselect : https://github.com/faassen/reselect๋ฅผ ํ™•์ธ

@gaearon ์ฟจ! ReactEurope BTW์—์„œ ๋ฉ‹์ง„ ์ด์•ผ๊ธฐ! ๊ฐ์‚ฌ.

์ด๊ฒƒ์€ redux 1.0.0, https://github.com/gajus/redux-immutable ๊ณผ ํ•จ๊ป˜ Immutable.js๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ์‹œ๋„์ž…๋‹ˆ๋‹ค.

์ข‹์€ @gajus! ์ง€๊ธˆ redux-immutable ํ…Œ์ŠคํŠธํ•˜๊ณ  https://github.com/gajus/canonical-reducer-composition ํŒจํ„ด์„ ์ •๋ง ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

@chiplay ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐํ•จ์ด ์žˆ๊ฑฐ๋‚˜ ๊ฐœ์„  ํ•  ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ํ”ผ๋“œ๋ฐฑ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

redux์™€ ํ•จ๊ป˜ ๋ถˆ๋ณ€ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์ ์ด ์žˆ์Šต๋‹ˆ๊นŒ? redux๊ฐ€ ๋ถˆ๋ณ€์˜ ํ–‰๋™์„ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๋Š” ๊ฒฝ์šฐ (์˜ˆ : ์ €์žฅ์†Œ๊ฐ€ ์ƒํƒœ์˜ ์ƒˆ๋กœ์šด ์‚ฌ๋ณธ์„ ๋ฐ˜ํ™˜)? ์„ฑ๋Šฅ (์–ด๋–ค ๋ฒค์น˜ ๋งˆํฌ?)? ๋˜๋Š” ๋‹ค๋ฅธ ๊ฒƒ? ๊ณ ๋งˆ์›Œ

๋ฟก๋ฟก

Redux์™€ ํ•จ๊ป˜ Immutable ์‚ฌ์šฉ์˜ ์žฅ์  :

  • ์‹ค์ˆ˜๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋Œ€ํ˜• ์–ด๋ ˆ์ด ๋ฐ ๊ฐ์ฒด๋กœ ๋” ๋น ๋ฅธ ์„ฑ๋Šฅ๊ณผ ๋” ๋‚˜์€ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„

Redux์™€ ํ•จ๊ป˜ Immutable ์‚ฌ์šฉ์˜ ๋‹จ์  :

  • ํŒ€์„ ์œ„ํ•ด ๋ฐฐ์šธ ์ˆ˜์žˆ๋Š” ์ƒˆ๋กœ์šด API
  • ๋ฒˆ๋“ค ํฌ๊ธฐ ์ฆ๊ฐ€
  • ๋””๋ฒ„๊ทธ๊ฐ€ ์•ฝ๊ฐ„ ๊นŒ๋‹ค ๋กญ์Šต๋‹ˆ๋‹ค.

ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„๋Š” ๋‹น์‹ ์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค!

@gaearon
๋น ๋ฅด๊ณ  ๋„์›€์ด๋˜๋Š” ๋‹ต๋ณ€์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

Redux ํ‘œ์ค€์„ ์ค€์ˆ˜ํ•˜๋Š” ImmutableJs ๋ฐ Redux๋ฅผ ์›ํ•œ๋‹ค๋ฉด https://github.com/indexiatech/redux-immutablejs๋ฅผ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon ์›น ์‚ฌ์ดํŠธ์— ๋งํฌ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

Asaf ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ์œ ์šฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

2015 ๋…„ 9 ์›” 4 ์ผ 18:36์— Asaf Shakarchi [email protected] ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

Redux ํ‘œ์ค€์„ ์ค€์ˆ˜ํ•˜๋Š” ImmutableJs ๋ฐ Redux๋ฅผ ์›ํ•œ๋‹ค๋ฉด https://github.com/indexiatech/redux-immutablejs๋ฅผ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon ์›น ์‚ฌ์ดํŠธ์— ๋งํฌ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

โ€”
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.

@asaf

์ข‹์€ ์ผ์ž…๋‹ˆ๋‹ค. Ecosystem.md PR์„ ํ•ด์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
ํ”„๋กœ์ ํŠธ์— ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ธฐ๊บผ์ด ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@gaearon ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ, PR : https://github.com/rackt/redux/pull/707

๊ฐ์‚ฌ!

์•ˆ๋…•ํ•˜์„ธ์š”,
@gaearon์— ๋Œ€ํ•œ ์•ฝ๊ฐ„์˜ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๊ธฐ์กด React / Redux ์•ฑ์—์„œ ImmutableJS๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰ ํ•œ ๋น ๋ฅธ ํ…Œ์ŠคํŠธ์—์„œ ์•ฝ๊ฐ„ ๋Š๋ฆฌ๊ฒŒ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ ์‚ฌ๋ก€ : API ํ˜ธ์ถœ์—์„œ ๋ฐ์ดํ„ฐ ๋ชจ์Œ์„ ๊ฐ€์ ธ ์™€์„œ ๊ฐ์†๊ธฐ์— ์ €์žฅ ...

๋‚ด ๊ฐ์†๊ธฐ์—์„œ
ImmutableJS์—†์ด โ€‹โ€‹:

const initialStore = {
    isLoading : false,
    error     : null,
    data      : []
}

// in the switch case
return {
   ...state,
   isLoading: false,
   error: null,
   data: action.result
}

ImmutableJS ์‚ฌ์šฉ

const initialStore = Map({
    isLoading : false,
    error     : null,
    data      : List()
})

// in the handler function
return state.merge({
    isLoading: false,
    error: null,
    data: List(result.result)
})

ImmutableJS "์น˜๋ฃŒ"๊ฐ€ ์—ฌ๊ธฐ์—์„œ ๋” ๋งŽ์€ ๋น„์šฉ์ด ๋“ค์ง€ ์•Š๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

Immutability์—์„œ ์ดํ•ด ํ•œ ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด ๋ Œ๋”๋ง์ด ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰๋  ๋•Œ ์ด์ ์ด ๋” ๋งŽ์Šต๋‹ˆ๋‹ค.

์˜๊ฒฌ์„ ๋ณด๋‚ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด์ ์€ ๋Œ€ํ˜• ์–ด๋ ˆ์ด ๋ฐ ๊ฐ์ฒด์—์„œ ์ž‘๋™ํ•˜๋Š” ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ๋น„์šฉ์ด ์ ๊ฒŒ ๋“ค๊ณ  ๋” ๋น ๋ฅด๊ฒŒ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ž‘์€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ํฐ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์•Œ์•˜์–ด ๊ณ ๋งˆ์›Œ.
๊ทธ๋ž˜์„œ ๋‚˜๋Š” ์–ด์จŒ๋“  ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

๋„ค, ์ž˜ ์–ด์šธ๋ฆฝ๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€์žˆ์—ˆ์Šต๋‹ˆ๋‹ค .. ๐Ÿ’ฏ

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