최근에 스터디서치 웹을 React 프레임워크와 Flux 구조를 사용해 리뉴얼했다. Flux 구조를 사용하면서 느낀 Flux의 장점과 겪었던 문제, 해결방법을 짧게나마 공유해보려고 한다.
Flux의 장점
웹은 모바일 앱처럼 한 화면에 하나의 MVC셋이 아닌 한 화면에 여러 컴포넌트들이 존재할 여지가 있다. Flux는 이러한 웹 특성에 잘 맞는 구조다.
1. Single source of truth
위 사진에서 내 프로필 정보를 사용하고 있는 컴포넌트는 오른쪽 위의 마이페이지 링크와 중간 위쯤 있는 마이페이지 내에서의 네비게이션, 그리고 프로필 수정 페이지 총 세개다. 이 세개의 컴포넌트는 각기 다른 모델 객체를 사용하는 것이 아닌, 스토어에서 제공하는 하나의 데이터만을 사용한다.
2. Event handling
프로필 사진이나 이름을 변경하게되면 스토어에 변경사항이 저장되고, 스토어는 변경사항을 알림받아야 할 컴포넌트들에 데이터가 변경되었음을 알려준다. 따라서 한 컴포넌트에서 변경 이벤트가 발생할지라도, 이 컴포넌트가 데이터 변경을 알리기 위해 다른 컴포넌트들을 참조할 필요가 없다.
부수적인 이벤트 처리
Flux구조의 장점을 지키려면 데이터는 단방향으로 흘러야하며, 컴포넌트가 데이터를 직접 참조하거나 변경해서는 안된다. 그렇다면 이벤트 완료 후 완료 알림과 같은 부수적인 이벤트들은 어떻게 처리할까? 처음에는 별 고민없이 ChangeListener에서 처리를 해주었다.
...
componentDidMount: function() {
MySelfStore.addPhotoChangeListener(this._onPhotoChange);
MySelfStore.addNameChangeListener(this._onNameChange);
...
},
componentWillUnmount: function() {
MySelfStore.removePhotoChangeListener(this._onPhotoChange);
MySelfStore.removeNameChangeListener(this._onNamgeChange);
...
},
_onPhotoInput: function() {
MySelfActions.changePhoto(...);
},
...
_onPhotoChange: function() {
ToastActions.show("사진이 변경되었습니다");
this.setState({mySelf: MySelfStore.getMySelf()});
}
...
이런 구조는 몇가지 단점이 있는데, 우선 데이터 변경이 해당 컴포넌트에서 발생된 이벤트에 의해 이뤄진 것인지 확인하지 못한다. 또 이벤트 발생 부분과 완료부분이 떨어져있어 코드의 가독성도 떨어진다. 마지막으로 저렇게 하다간 수많은 ChangeListener가 존재해 코드가 상당히 무거워질 것이다. 이를 해결하기 위해 Promise 패턴을 이용하였다.
...
componentDidMount: function() {
MySelfStore.addChangeListener(this._onMySelfChange);
},
componentWillUnmount: function() {
MySelfStore.removeChangeListener(this._onMySelfChange);
},
_onBookmarkButtonClick: function() {
MySelfActions.changePhoto(...).done(function() {
ToastActions.show("사진이 변경되었습니다");
}
},
_onMySelfChange: function() {
this.setState({mySelf: MySelfStore.getMySelf()});
}
...
이렇게 함으로써 onPhotoChange, onNameChange와 같은 ChangeListener들을 줄여 코드를 가볍게 할 수 있었고, 이벤트 완료와 데이터 변경을 나누어 처리할 수 있어 가독성도 높힐 수 있었다.
댓글 없음:
댓글 쓰기