Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

다함께, FluxUtils 한바퀴!

10,575 views

Published on

.

Published in: Software
  • Be the first to comment

다함께, FluxUtils 한바퀴!

  1. 1. 다같이! FluxUtils 한바퀴
  2. 2. React를 사용해 진행했던 두 프로젝트 AJAX : SuperAgent Pub/Sub : EventEmitter3 View: React Router: page.js
  3. 3. React를 사용해 진행했던 두 프로젝트 AJAX : SuperAgent Pub/Sub : EventEmitter3 View: React Router: page.js 라이브러리만 조합해 협업할 때 발생하는 다양한 문제들 적당한 수준의 구조와 개발자 간 공통적으로 이해할 수 있는 규칙이나 철학 필요
  4. 4. React와 궁합이 좋은 Flux 계열을 한번 살펴보자! “ ”
  5. 5. FluxUtils를 사용한 이유 약 3개월 전 JSer.info를 통해 플럭스유틸즈에 관해 알게 됐다. 그리고 다음과 같은 고민을 하게 됐다.
  6. 6. FluxUtils
  7. 7. ReduxFluxUtils
  8. 8. ReduxFluxUtils
  9. 9. 클래스로 디자인 돼 있다. 함수로 디자인 돼 있다. 메서드로 reduce를 제공한다. ReduxFluxUtils
  10. 10. ReduxFluxUtils
  11. 11. todo/complete 액션에 맞춰 상태를 변경하고 반환한다. DELETE_TODO 액션에 따라 상태를 변경하고 반환한다. ReduxFluxUtils
  12. 12. ReduxFluxUtils “ ” 두 라이브러리는 닮은 부분이 있다. 두 개발자는 웹 상에서 열정적으로 의견을 주고 받으며 서로에게 영향을 주고 있다. https://goo.gl/3PDL8X https://goo.gl/iww0V9&
  13. 13. FluxUtils 페이스북의 웹 개발자 빌 피셔(Bill Fisher)가 개발해 제공하는 기본 유틸리티 클래스 집합 이벤트 중앙 허브 격인 「Dispatcher」만제공하는 처음과 달리 다양한 Store와 Container를 실체화해 제공
  14. 14. FluxStore FluxReduceStore FluxMapStore FluxContainer
  15. 15. Store의 기반클래스, EventEmitter를 의존하고 Dispatcher를 구독하여 Flux 아키텍처 흐름의 기본을 실현함“ ” FluxStore
  16. 16. FluxStore (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82
  17. 17. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82 FluxStore
  18. 18. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82 FluxStore는 EventEmitter를 의존한다. FluxStore
  19. 19. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82 FluxStore
  20. 20. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82 생성자를 통해 Dispatcher의 인스턴스를 주입받는다. Dispatcher와 EventEmitter의 인스턴스를 프로퍼티로 설정한다. FluxStore
  21. 21. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82 FluxStore
  22. 22. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L15-L18 #L72-L82 Dispatcher의 register 메서드에 익명함수를전달해해당Dispatcher의 액션을 구독한다. FluxStore
  23. 23. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L149-L155 #L28-L54 FluxStore
  24. 24. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L149-L155 #L28-L54 __onDispatch 메서드는 추상메서드다. EventEmitter의 emit 메서드를 통해 자신의 상태 변화를 발행한다. FluxStore
  25. 25. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L149-L155 #L28-L54 FluxStore
  26. 26. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L130-L137 #L28-L54 FluxStore
  27. 27. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) #L130-L137 #L28-L54값이 변경되면 __emitChange 메서드를 호출해 __changed 프로퍼티를 true로 설정한다. FluxStore
  28. 28. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) DispatcherFluxStore FluxStore
  29. 29. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) DispatcherregisterFluxStore FluxStore
  30. 30. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) addListener FluxContainer DispatcherregisterFluxStore FluxStore
  31. 31. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) addListener Component FluxContainer DispatcherregisterFluxStore FluxStore
  32. 32. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) addListener Component FluxContainer DispatcherregisterFluxStore render FluxStore
  33. 33. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) FluxContainer FluxStore Component Dispatcher FluxStore Action
  34. 34. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) FluxContainer FluxStore Component Dispatcher FluxStore AjaxAction
  35. 35. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) FluxContainer FluxStore Component Dispatcher FluxStore AjaxAction dispatch
  36. 36. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) FluxContainer FluxStore Component payload FluxStore Ajax Dispatcher Action dispatch
  37. 37. (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) FluxContainer FluxStore Component Dispatcherpayload emit FluxStore AjaxAction dispatch
  38. 38. FluxStore (https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js) FluxContainer rerender FluxStore Component Dispatcherpayload emit AjaxAction dispatch
  39. 39. Store를 상속한 클래스 Redux와 비슷한 reduce 메서드 지원“ ” FluxReduceStore
  40. 40. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L22-L45 FluxReduceStore
  41. 41. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L22-L45 FluxReduceStore
  42. 42. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L22-L45 생성자에서 getInitialState 메서드를 호출한다. FluxReduceStore
  43. 43. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L22-L45 FluxReduceStore
  44. 44. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L22-L45 getInitialState는 추상 메서드로 구체 클래스에서 정의해야한다. FluxReduceStore
  45. 45. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  46. 46. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  47. 47. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 Dispatcher의 액션을 전달 받는 메서드가 재정의 돼 있다. FluxReduceStore
  48. 48. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  49. 49. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 reduce 메서드를 호출한다. FluxReduceStore
  50. 50. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  51. 51. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  52. 52. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 reduce 메소드 역시 추상 메서드로 구체 클래스에서 정의해야한다. FluxReduceStore
  53. 53. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L66-L71 FluxReduceStore
  54. 54. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L66-L71 FluxReduceStore
  55. 55. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L66-L71 FluxReduceStore
  56. 56. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L66-L71 FluxReduceStore
  57. 57. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L66-L71 다음과 같은 형태로 정의될 수 있다. FluxReduceStore
  58. 58. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  59. 59. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  60. 60. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 기존의 상태 값과 reduce의 결과 값 이 다른지 비교한다. FluxReduceStore
  61. 61. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  62. 62. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 다르다면 값을 변경한다. __emitChange 메서드를 호출해 __changed 프로퍼티를 true로 변경한다. FluxReduceStore
  63. 63. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 FluxReduceStore
  64. 64. (https://github.com/facebook/flux/blob/master/src/stores/FluxReduceStore.js) #L47-L94 최종적으로 emit 하여 상태 변화를 구독자 에게 알린다. FluxReduceStore
  65. 65. “ ” FluxMapStore ReduceStore를 상속한 클래스 Store의 상태를 기본적으로 Immutable.Map 으로 선언하고 그와 관련한 몇 가지 메서드를 추가한 클래스
  66. 66. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L40-L44 #L59-L72 FluxMapStore
  67. 67. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L40-L44 #L59-L72 FluxMapStore
  68. 68. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L40-L44 #L59-L72 getInitialState 메서드가 정의돼 있고 상태로 Immutable.Map을 반환한다. FluxMapStore
  69. 69. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L40-L44 #L59-L72 FluxMapStore
  70. 70. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L40-L44 #L59-L72 FluxMapStore
  71. 71. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L40-L44 #L59-L72Immutable.Map에서 값을 가져오기 위한 일부 메서드가 정의돼 있다. FluxMapStore
  72. 72. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L26-L37 FluxMapStore
  73. 73. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L26-L37 FluxMapStore
  74. 74. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L26-L37 상태는 Immutable.Map 이므로 관련 API를 사용해 값을 변경한다. FluxMapStore
  75. 75. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L26-L37 FluxMapStore
  76. 76. (https://github.com/facebook/flux/blob/master/src/stores/FluxMapStore.js) #L26-L37 컴포넌트에서는 다음과 같이 사용할 수 있다. FluxMapStore
  77. 77. “ ” FluxContainer 자체적으로 관리하는 State와 Props 없이 Store와 Component의 중간 매개체 역할을 하는 단순한 컨테이너 클래스
  78. 78. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) FluxContainer
  79. 79. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) FluxContainer
  80. 80. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) Container에서 관심있어 하는 Store를 반환한다. FluxContainer
  81. 81. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) FluxContainer
  82. 82. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) componentWillReceiveProps 라이프 사이클 메서드에서 호출된다. Store의 값을 이용해 상태를 변경한다. FluxContainer
  83. 83. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) FluxContainer
  84. 84. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) 설정된 상태를 하위 컴포넌트에 전달한다. FluxContainer
  85. 85. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 FluxContainer
  86. 86. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 FluxContainer
  87. 87. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 componentDidMount 라이플 사이클 메서드에서 getStores 메서드를 통해 관계를 맺는 Store 리스트를 얻는다. FluxContainer
  88. 88. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 FluxContainer
  89. 89. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 Store 리스트를 순회하며 addListener 메서드를 호출해 상태 변화를 구독한다. FluxContainer
  90. 90. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 FluxContainer
  91. 91. (https://github.com/facebook/flux/blob/master/src/stores/FluxContainer.js) #L60-L75 #L92-L109 componentWillReceiveProps 라이프 사이클 메서 드에서 calculateState 메서드를 호출하며 이 메서 드에서 반환되는 값을 setState 한다. FluxContainer
  92. 92. FluxUtils 기반으로 개발한 사내 회의실 예약 웹 애플리케이션
  93. 93. 만들면서 느낀 몇 가지 규칙을 정리
  94. 94. 규칙 1. Container에서 자체적으로 상태를 다루거나 이벤트를 처리하지 않는다. Container는 Store를 구독하고 Store의 상태 값을 하위 컴포넌트에 전달하는 역할로만 적합하다.
  95. 95. 일반적인 방법으로 컴포넌트 독자적인 상태를 선언했다.
  96. 96. ?
  97. 97. undefined
  98. 98. undefined 기존 컴포넌트의 방식대로 상태를 다룰 수 없다. setState()를 호출해도 예상대로 동작하지 않는다.
  99. 99. Container에서 이벤트를 처리하기 시작하면 상태가 필요해지며 결국 Container의 구조가 깨져 관리하기 힘들어진다.
  100. 100. FluxStore Component FluxStore Component 구독 FluxContainer 전달 Container에서 이벤트를 처리하기 시작하면 상태가 필요해지며 결국 Container의 구조가 깨져 관리하기 힘들어진다.
  101. 101. FluxStore Component FluxStore Component 구독 FluxContainer 전달 Container는 오로지 컴포넌트와 Store의 중간 다리 역할로써 사용 한다. Container에서 이벤트를 처리하기 시작하면 상태가 필요해지며 결국 Container의 구조가 깨져 관리하기 힘들어진다.
  102. 102. 규칙 2. 특정 컴포넌트의 상태를 다른 컴포넌트에서도 알아야 한다면 Store에 값 추가를 고려한다. 컴포넌트가 컴포넌트를 의존하는 기괴한 형태나 두 컴포넌트를 연결하기 위한 랩퍼 컴포넌트를 늘리지 않는다.
  103. 103. sidebar content
  104. 104. sidebar content Splitter
  105. 105. sidebar—minimal content—extend
  106. 106. AppStore 클래스를 생성하고 extended 상태 값을 선언한다.
  107. 107. TOGGLE_EXTEND_MODE 액션이 전달되면 extended 값을 반전하여 상태를 재설정한다.
  108. 108. Spliiter 컴포넌트의 클릭 이벤트가 발생하면 TOGGLE_EXTEND_MODE 액션을 디스패치한다.
  109. 109. 상태 값이 변경되면 리렌더링 되며 두 컴포넌트의 UI 상태가 변경된다.
  110. 110. ContentSidebar AppStore FluxContainer
  111. 111. ContentSidebar AppStore FluxContainer
  112. 112. ContentSidebar AppStore FluxContainer
  113. 113. ContentSidebar AppStore FluxContainer
  114. 114. ContentSidebar AppStore FluxContainer 두 컴포넌트를 잇는 랩퍼 컴포넌트를 작성하다보면 랩퍼컴포넌트에책임이몰리거나경계가모호해지는 경향이 있고, 애플리케이션이 커질 수록 많은 랩퍼 컴포넌트가양상되는문제점도있다.
  115. 115. 규칙 3. AJAX나 이벤트에 따른 Dispatch는 Action으로 추상화한다. 컴포넌트에서 Ajax를 직접 사용하면 컴포넌트의 독립성이 저하되고 재사용하기 힘들어진다.
  116. 116. ReservationSection Splitter Time Details Sidebar Timeline
  117. 117. ReservationSection Splitter Time Details Sidebar Timeline Dispatch & AJAX Dispatch & AJAX Dispatch & AJAX Dispatch & AJAX Dispatch & AJAX Dispatch & AJAX
  118. 118. ReservationSection Splitter Time Details Sidebar Timeline
  119. 119. ReservationSection Splitter Time Details Sidebar Timeline Dispatch Ajax Call Call Actions
  120. 120. https://github.com/facebook/flux/tree/master/examples/flux-chat/js
  121. 121. MessageComposer.react.js https://github.com/facebook/flux/blob/master/examples/flux-chat/js/components/MessageComposer.react.js
  122. 122. MessageComposer.react.js https://github.com/facebook/flux/blob/master/examples/flux-chat/js/components/MessageComposer.react.js
  123. 123. https://github.com/facebook/flux/blob/master/examples/flux-chat/js/actions/ChatMessageActionCreators.js CheatMessageActionCreators.js
  124. 124. https://github.com/facebook/flux/blob/master/examples/flux-chat/js/actions/ChatMessageActionCreators.js CheatMessageActionCreators.js
  125. 125. ChatWebAPIUtils.js https://github.com/facebook/flux/blob/master/examples/flux-chat/js/utils/ChatWebAPIUtils.js
  126. 126. https://github.com/facebook/flux/blob/master/examples/flux-chat/js/utils/ChatWebAPIUtils.js ChatWebAPIUtils.js
  127. 127. https://github.com/facebook/flux/blob/master/examples/flux-chat/js/actions/ChatServerActionCreators.js ChatServerActionCreators.js
  128. 128. https://github.com/facebook/flux/blob/master/examples/flux-chat/js/actions/ChatServerActionCreators.js ChatServerActionCreators.js
  129. 129. MessageComposer CheatMessae
 ActionCreators ChatWebAPIUtils ChatServer
 ActionCreators
  130. 130. MessageComposer CheatMessae
 ActionCreators ChatWebAPIUtils ChatServer
 ActionCreators createMessage()
  131. 131. MessageComposer CheatMessae
 ActionCreators ChatWebAPIUtils ChatServer
 ActionCreators createMessage() dispatch()
  132. 132. MessageComposer CheatMessae
 ActionCreators ChatWebAPIUtils ChatServer
 ActionCreators createMessage() dispatch() createMessage()
  133. 133. MessageComposer CheatMessae
 ActionCreators ChatWebAPIUtils ChatServer
 ActionCreators createMessage() dispatch() createMessage() receiveCreatedMessage()
  134. 134. MessageComposer CheatMessae
 ActionCreators ChatWebAPIUtils ChatServer
 ActionCreators createMessage() dispatch() createMessage() receiveCreatedMessage()
  135. 135. ActionCreators Utils 물리적으로 나눠 놓은 두 개념의 관심사가 섞여 있다는 느낌 억지로 뜯어 놓은 느낌이 강하고 객체의 흐름을 복잡하게 한다.
  136. 136. ActionCreators Utils 그렇다면 두 개념의 관심사를 다시 나눠보자.
  137. 137. CheatMessaeActionCreators.js
  138. 138. CheatMessaeActionCreators.js Utils에서 ActionCreators 객체를 직접 호출하는게 아니라, ActionCreators에서 Dispatch와 관련한 모든 업무를 담당한다.
  139. 139. ChatWebAPI.js
  140. 140. ChatWebAPI.js Utils가 아니라 Ajax 요청을 담당하는 미들웨어를 만들고 이 객체에서는 오로지 Ajax 요청만 담당한다.
  141. 141. MessageComposer CheatMessae
 ActionCreators ChatWebAPI
  142. 142. MessageComposer CheatMessae
 ActionCreators createMessage() ChatWebAPI
  143. 143. MessageComposer CheatMessae
 ActionCreators createMessage() dispatch() ChatWebAPI
  144. 144. MessageComposer CheatMessae
 ActionCreators createMessage() createMessage() dispatch() ChatWebAPI
  145. 145. MessageComposer CheatMessae
 ActionCreators createMessage() createMessage() Promise dispatch() ChatWebAPI
  146. 146. MessageComposer CheatMessae
 ActionCreators createMessage() createMessage() Promise dispatch() dispatch() ChatWebAPI
  147. 147. 규칙 4. Store에서 AJAX를 호출하지 않는다 Store는 비동기 로직을 작성하기 적합 하지 않다.
  148. 148. 클래스의 구현 로직, 사용 예제를 살펴보면 Store는 비동기 로직을 고려해 디자인돼 있지 않다는 사실을 알 수 있다.
  149. 149. Actions 객체에서 AJAX를 요청하고, AJAX 요청 결과를 액션을 통해 Store로 전달하는게 가장 자연스러운 형태다.
  150. 150. 규칙5. UI가 크게 변경되거나 Container가 커진 다면 URL 디자인을 고려한다. 하나의 URL에 너무 많은 요소를 담을 때 Container는 거대해지고 관리하기힘들어 진다.
  151. 151. UI가 복잡해 짐에도 하나의 URL로 모든 인터렉션을 처리하면 Container가 크게 복잡해진다.
  152. 152. return ( <div> <Header date={params.date}/> <Sidebar date={params.date} minimal={this.state.extended}/> <Content extend={this.state.extended}> <TimeGutter start={startTime} end={endTime}/> <Schedule> <RoomTypes rooms={roomList}/> <Timeline date={params.date} rooms={roomList} events={this.state.events} profile={this.state.profile} start={startTime} end={endTime} /> </Schedule> <Popover date={params.date} options={this.state.popover}/> </Content> <Preloader show={this.state.loading}/> <ModalReservation date={params.date} show={true} rooms={roomList} users={this.state.users} values={this.state.creating} start={startTime} end={endTime} /> </div> ); 예약 현황을 출력하는 컴포넌트 조합 회의실 예약 시 사용하는 예약 하기 모달 창
  153. 153. http://OOO.com/calendar/2015-11-30 http://OOO.com/calendar/2015-11-30/create 예약 현황 보기 회의실 예약 하기
  154. 154. URL을 잘 디자인하면 Container의 책임을 적절히 나눌 수 있고, 가볍게 관리할 수 있다.
  155. 155. 감사합니다.

×