Flux in reactjs
1. Flux là gì? Flux và ReactJS cùng được tạo ra bởi Facebook để giải quyết một số những vấn đề rất đặc thù của bản thân Facebook Trước khi có Flux và React thì hệ thống model và view của facebook như sau: Do tương tác của người dùng là ở View nên đôi khi View cần phải update ngược lại ...
1. Flux là gì?
- Flux và ReactJS cùng được tạo ra bởi Facebook để giải quyết một số những vấn đề rất đặc thù của bản thân Facebook
- Trước khi có Flux và React thì hệ thống model và view của facebook như sau:
- Do tương tác của người dùng là ở View nên đôi khi View cần phải update ngược lại dữ liệu ở Model khác. Điều này dẫn đến hiệu ứng "thác nước" khi một hành động của người dùng trigger một loạt các thay đổi, mỗi thay đổi lại có thể trigger ra một loạt các thay đổi khác, và tất cả các thay đổi là quá trình bất đồng bộ. Và nhìn vào mô hình trên sẽ khó khăn rất lớn khi debug nếu có lỗi xảy ra
Giải pháp: Luồng dữ liệu một hướng và Flux đã ra đời:
-
Flux là architecture hơn là một framework hay một library
-
Sử dụng cho việc xây dựng client-side web applications
-
Nó bổ sung khả năng kết hợp các view components của React bằng việc sử dụng một unidirectional data flow(dữ liệu một chiều)
- View : là các React Component.
- Store: là nơi chứa, xử lý dữ liệu cho App.
- Action: là nơi khởi tạo action.
- Dispatcher: là nơi phát action.
1.1 Action Creators
- Action Creators có nhiệm vụ tạo ra các action, là bước đầu tiên trong luồng mà các thay đổi và tương tác đều đi qua. Bất cứ khi nào trạng thái của web app hay là render của view thay đổi thì đầu tiên sẽ là một hành động được tạo ra.
- Sau khi The Action Creator tạo ra action, anh ta sẽ gửi nó cho The dispatcher.
1.2 The dispatcher
- The dispatcher về cơ bản là một tập hợp rất nhiều các callbacks. Khi một action được gửi đến The dispatcher, nó sẽ gửi chúng đến store tương ứng theo quy tắc đồng bộ.
1.3 The Store
- The store là nơi chứa toàn bộ các trạng thái và logic chuyển trạng thái của app.Tất cả mọi thay đổi trạng thái đều được thực thi trực tiếp ở đây.
- Mỗi khi bạn muốn thay đổi một trạng thái, bạn cần phải tạo một action, submit vào The action creator, đi qua The dispatcher rồi mới được The store xử lý.
- Một store sẽ nhận rất nhiều các action, và trong store thường sẽ có một cấu trúc switch để quyết định xem có cần phải quan tâm đến action hay không.
1.4 The controller view and the view
- The view có nhiệm vụ thu nhận lệnh thay đổi trạng thái và render hiển thị, cũng như nhận input từ người dùng.
- Controller view như là một nhà quản lý cấp nhỏ đứng giữa store và view, nhận thông báo khi trạng thái thay đổi, tổng hợp những nội dung cần thay đổi và truyền đến những view trực thuộc.
Để rõ hơn về cấu trúc hoạt động của flux, sau đây tôi sẽ trình bày 1 demo nhỏ về crud bằng reactjs và flux
-
Yêu cầu bài toán là người sử dụng biết về reactjs cơ bản và sử dụng jsx và biết component và state và props
-
Bài toán đặt ra là xây dựng một app có đầy đủ các chức năng cơ bản:
- Xem danh sách bài viết
- Các chức năng chính như: create, update, delete, search
-
Đây là cấu trúc thư mục reactjs với rails
Nhìn vào hình vẽ trên ta có thể thấy đầy đủ các thành phần của flux in reactjs như folder actions, dispatcher, stroes, hay components...
- Sau đây tôi xin đi chi tiết vào một chức năng đơn giản nhất đó là remove một article khỏi danh sách:
- Khi Remove Article, chúng ta sẽ phải tìm id của article cần xóa và hiển thị lại thông tin danh sách articles. Sau đây là source code của component remove-from-article
###* @jsx React.DOM ### define [ "react-with-addons" "actions/app-actions" ], (React, AppActions) -> "use strict" removeFromArticle = React.createClass( handleClick: (e) -> AppActions.removeArticle @props.index render: -> `<button onClick={this.handleClick}>-</button>` ) removeFromArticle
Khi click button remove article, Action removeArticle sẽ được gọi, đồng thời truyền theo thông tin id của article đang được chọn. AppActions là nơi đăng ký các Action của ứng dụng và chuyển tải thông tin (payload) tới Dispatcher.
Hãy cùng xem ../actions/app-actions.js thực hiện những công việc gì:
define [ "actions/constants" "dispatcher/app-dispatcher" ], (Constants, AppDispatcher)-> "use strict" AppActions = removeArticle: (index)-> AppDispatcher.handleViewAction(actionType: Constants.REMOVE_ARTICLE, index: index) AppActions
Như trên chúng ta đã gọi đến function removeArticle của AppActions kèm theo thông tin id của article mà chúng ta chọn. Khi này AppActions sẽ chuyển các thông tin cho Dispatcher:
- actionType: tên của Action, để thuận tiện cho việc đặt tên Action chúng ta quản lý thông qua AppConstants(chủ yếu để quản lý các text tĩnh đặt tên cho Action):
define [], -> "use strict" REMOVE_ARTICLE: "REMOVE_ARTICLE"
Theo luồng hoạt động của Flux, hãy xem sau khi Action truyền thông tin cho Dispatcher thì Dispatcher sẽ xử lý thông tin và thông báo cho Store. Hãy xem file ../dispatcher/app-dispatcher.js:
define [ "jquery" "dispatcher/dispatcher" ], ($, Dispatcher)-> "use strict" AppDispatcher = $.extend(Dispatcher.prototype, { handleViewAction: (action)-> @dispatch( source: 'VIEW_ACTION' action: action ) }) AppDispatcher
Ta có thể thấy function handleViewAction mà AppActions của chúng ta vừa gọi đến lúc trước. Khi này AppDispatcher sẽ phát lệnh gửi thông tin tới các Store.
File ../stores/app-stores.js
define [ "jquery" "lodash" "dispatcher/app-dispatcher" "actions/constants" "eventemitter2" ], ($, _, AppDispatcher, Constants, EventEmitter)-> "use strict" CHANGE_EVENT = "change" _articles = [] _removeArticle = (index)-> _articles.splice(index, 1) AppStore = $.extend(new EventEmitter(), { emitChange: -> @emit(CHANGE_EVENT) addChangeListener: (callback)-> @on(CHANGE_EVENT, callback) removeChangeListener: (callback)-> @removeListener(CHANGE_EVENT, callback) getArticle: -> _articles dispatcherIndex: AppDispatcher.register((payload)-> action = payload.action switch action.actionType when Constants.REMOVE_ARTICLE then _removeArticle(action.index) AppStore.emitChange() ) })
AppStores đã đăng ký trước với Dispatcher để lắng nghe các Action. Sau khi thực hiện xóa article, AppStore tiến hành truyền sự kiện để thông báo tới cho các View dữ liệu lưu trữ đã được thay đổi nhờ sự trợ giúp của module EventEmitter