티스토리 뷰

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이글을 읽는 분들은 Redux를 도입하신 분, 또는 이제부터 React의 상태관리를 도입하려는 분일거라 생각합니다.

그렇습니다 "Redux 코드는 너무 길지만, 익숙해지면 괜찮겠지?" 라고 생각 하는 분들을 위한 글입니다.


자기자신은 Redux 도입파 였지만 front-end-handbook-2017에 이름이 올라있는 MobX에 관심이 생겨 조사해봤습니다.  그 결과, 이글을 쓰게 되었기 때문에 개인적으로 Redux보다 낫다고 느낀 이유를 적어보겠습니다.

  • 코드량이 압도적으로 줄어든다. 
  • Store개념이 알기 쉽다. 
  • inject를 활용하면 jsx를 pure하게 구현할 수 있다.
  • 데코레이터층이 존재한다.

코드량이 압도적으로 줄어든다

한개의 쌍방향의 값을 컴포넌트에 표시하기 위해서, Redux에서는 아래와 같은 작업이 필요합니다.

  • Reducer 에 initialState 값을 추가
  • Reducer 에 Object.assign 로 새로운 State 를 생성
  • ActionType 을 추가
  • ActionCreator 를 추가
  • ActionDispatch 하는 컴포넌트에서  ActionCreator 호출
  • 표시하려는 컴포넌트에서 Reducer 로부터  props 전달 (Connect)
  • 필요하다면, 표시하려는 컴포넌트로 부모 컴포넌트에서 props 전달 

아무리 익숙해져도 이 비효율적인 느낌이 사라지지 않습니다.

한편 MobX는 아래와 같이 구현가능합니다. 

  • Store 에 값을 추가
  • Store 의 값을 조작하는 함수를 추가
  • Store 를 조작하고 싶은 컴포넌트에서 함수를 실행 
  • Store 를 참조하는 컴포넌트에 observer를 선언 

단순히 diff가 소멸되는 것을 알수 있습니다.
매우 간단하지 않습니까?

Store개념이 알기 쉽다.

Redux에서 Store는 유일무이한 존재로, Developer에게는 은폐된 상태로 제공됩니다.  그리고 Reducer를 경유하는 것으로, Store의 값을 참조할 수 있습니다.  또한, ActionType・ActionCreator를 경유하여 Store의 값을 변경할 수 있습니다.  초심자가 "Redux 쓰기 힘드네" 라고 느끼는 것은 이런 점 때문이라고 생각합니다. 

Mobx에서는 이런 것이 없습니다.

컴포넌트가 참조하고 싶은 Store를 선언하여 참조합니다.

Store의 값을 변경하고 싶으면 Store에게 요청합니다.

매우 간단합니다.

stores/SomeStore.js

export default class SomeStore { @observable count // 추가한 값 increment = () => this.count++ // 추가한 함수 }

components/SomeComponent.js

const SomeComponent = ({ someStore }) => { return ( <div> <p>{ someStore.count }</p> <button onClick={ someStore.increment }> +1 </button> </div> ) }) // 필요한 Store 를 inject(주입)해서、 observe(구독)한다. export default inject('someStore')(observer(SomeComponent))

inject를 활용하면 jsx를 pure하게 구현가능

Redux에서는, Container로부터 전달받은 props의 필요한 값을 render전에 가져와서 jsx에 주입합니다. MobX에도 같은 순서가 필요하지만, mobx-react의 Provider와 inject를 사용하는 것으로 보기좋은 컴포넌트 정의를 할 수 있습니다.  mobx-react v4부터 추가된 inject의 mapperFunction 가 있기 때문입니다. 

  • props 를 추상화할 수 있습니다. 
  • propTypes가 보기 좋아집니다. 
  • mapping을 변경하면、서로 다른 observerComponent 를 export 할 수 있습니다.
  • Test하기 좋아집니다.

inject 의 mapperFunction 에 의해 추상화되는 것으로, 재활용성이 높아진 컴포넌트의 예를 들어보겠습니다.

components/todos.js

import Mobx, { inject } from 'mobx-react' export const Todos = ({ todos, count, add, remove }) => { return ( <div className="todos"> { todos.map((todo, i) => <Todo key={ i } index={ i } />) } <p className="todos-count">{ count }</p> <button onClick={ add }>addTodo</button> <button onClick={ remove }>removeTodo</button> </div> ) } export const OpenedTodos inject(s => ({ todos: s.todoStore.openedTodos, count: s.todoStore.openedCount, add: s.todoStore.addTodo, remove: s.todoStore.removeTodo, }))(Todos) export const ClosedTodos inject(s => ({ todos: s.todoStore.closedTodos, count: s.todoStore.closedCount, add: s.todoStore.addTodo, remove: s.todoStore.removeTodo, }))(Todos) Todos.propTypes = { todos: Mobx.PropTypes.observableArray, count: React.PropTypes.number, add: React.PropTypes.func, remove: React.PropTypes.func }

2017/02/27[수정]:mapperFunction을 이용하는 경우는 observer decorate 를 제거할 필요성이 있기때문에 수정합니다.

N.B. note that in this specific case neither NameDisplayer or UserNameDisplayer doesn't need to be decorated with observer, since the observable dereferencing is done in the mapper function

2017/03/09[수정 ]: inject는 위에 적은 대로 context참조를 binding하고 있기때문에, 안정적인 선택지라고 하기 어렵기때문에, 내용을 수정합니다. 

디코레이터층의 존재

여기서 말하는 디코레이터 층은  @ 의 es6 decorator 를 말하는 것이 아닙니다. 
Ruby on rails 의 DraperDecorator 와 비슷한 것으로 , Store 의 @computed 를 지칭합니다.
어플레케이션을 구성하는 중에, 어찌됐든 jsx안에 render에 관련된 로직이 늘어납니다.

이런 부분을 보완해주는 것이 @computed 입니다.

@observable 한 값이 변경될 경우, @computed 한 값도 변경되는 동작으로부터, 
자신의 안에서, DraperDecorator와 같은 이용이 가능하겠다고 생각했습니다. 

Redux에도 같은 처리를 하는 것이 가능하지만,
Reducer의 코드가 점점 보기 안좋아질 것으로 예상됩니다. 

결론

Redux를 도입했을 때의 이점은 DevTool이나 문서가 충실한점입니다.
MobX는 아직 걸음마수준입니다. 
자신처럼, redux-saga를 사용하는 경우에는, 비동기 동작의 취급등에 대한 부작용에 대해서도 생각해야 합니다. 

이 점에 대해서는, 다음 기회에 적어보겠습니다.  

2017/02/28[수정 ]:속편을 적어보았습니다.  >> 次のReact状態管理 MobXのStore考察 (요건 다음에 번역..)


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함