From 13925db2514d896acdca019c54e20883bfc47c59 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 12 Dec 2017 17:32:43 +0000 Subject: [PATCH] Refactor to allow dispatching of two kinds of Actions They are: 1. The existing type of Action, Objects with an `action` type. 1. Asyncronous Actions, functions that accept a `dispatch` argument, which can be used to dispatch Actions asyncronously. --- src/actions/GroupActions.js | 9 ++++----- src/actions/TagOrderActions.js | 11 +++++------ src/actions/actionCreators.js | 28 +++++++++++++-------------- src/components/structures/TagPanel.js | 6 +++--- src/dispatcher.js | 14 ++++++++++++-- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/actions/GroupActions.js b/src/actions/GroupActions.js index da321af18b..7ee5a40cdb 100644 --- a/src/actions/GroupActions.js +++ b/src/actions/GroupActions.js @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { createPromiseActionCreator } from './actionCreators'; +import { asyncAction } from './actionCreators'; const GroupActions = {}; -GroupActions.fetchJoinedGroups = createPromiseActionCreator( - 'GroupActions.fetchJoinedGroups', - (matrixClient) => matrixClient.getJoinedGroups(), -); +GroupActions.fetchJoinedGroups = function(matrixClient) { + return asyncAction('GroupActions.fetchJoinedGroups', () => matrixClient.getJoinedGroups()); +}; export default GroupActions; diff --git a/src/actions/TagOrderActions.js b/src/actions/TagOrderActions.js index 76d48bff99..cda2899104 100644 --- a/src/actions/TagOrderActions.js +++ b/src/actions/TagOrderActions.js @@ -15,14 +15,13 @@ limitations under the License. */ import Analytics from '../Analytics'; -import { createPromiseActionCreator } from './actionCreators'; +import { asyncAction } from './actionCreators'; import TagOrderStore from '../stores/TagOrderStore'; const TagOrderActions = {}; -TagOrderActions.commitTagOrdering = createPromiseActionCreator( - 'TagOrderActions.commitTagOrdering', - (matrixClient) => { +TagOrderActions.commitTagOrdering = function(matrixClient) { + return asyncAction('TagOrderActions.commitTagOrdering', () => { // Only commit tags if the state is ready, i.e. not null const tags = TagOrderStore.getOrderedTags(); if (!tags) { @@ -31,7 +30,7 @@ TagOrderActions.commitTagOrdering = createPromiseActionCreator( Analytics.trackEvent('TagOrderActions', 'commitTagOrdering'); return matrixClient.setAccountData('im.vector.web.tag_ordering', {tags}); - }, -); + }); +}; export default TagOrderActions; diff --git a/src/actions/actionCreators.js b/src/actions/actionCreators.js index b92e8ed950..8e1423d6c3 100644 --- a/src/actions/actionCreators.js +++ b/src/actions/actionCreators.js @@ -14,25 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -import dis from '../dispatcher'; - /** - * Create an action creator that will dispatch actions asynchronously that - * indicate the current status of promise returned by the given function, fn. + * Create an asynchronous action creator that will dispatch actions indicating + * the current status of the promise returned by fn. * @param {string} id the id to give the dispatched actions. This is given a - * suffix determining whether it is pending, successful or - * a failure. - * @param {function} fn the function to call with arguments given to the - * returned function. This function should return a Promise. - * @returns {function} a function that dispatches asynchronous actions when called. + * suffix determining whether it is pending, successful or + * a failure. + * @param {function} fn a function that returns a Promise. + * @returns {function} a function that uses its single argument as a dispatch + * function. */ -export function createPromiseActionCreator(id, fn) { - return (...args) => { - dis.dispatch({action: id + '.pending'}); - fn(...args).then((result) => { - dis.dispatch({action: id + '.success', result}); +export function asyncAction(id, fn) { + return (dispatch) => { + dispatch({action: id + '.pending'}); + fn().then((result) => { + dispatch({action: id + '.success', result}); }).catch((err) => { - dis.dispatch({action: id + '.failure', err}); + dispatch({action: id + '.failure', err}); }); }; } diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 9bf5a12731..e3b8c70027 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -68,7 +68,7 @@ const TagPanel = React.createClass({ }); }); // This could be done by anything with a matrix client - GroupActions.fetchJoinedGroups(this.context.matrixClient); + dis.dispatch(GroupActions.fetchJoinedGroups(this.context.matrixClient)); }, componentWillUnmount() { @@ -81,7 +81,7 @@ const TagPanel = React.createClass({ _onGroupMyMembership() { if (this.unmounted) return; - GroupActions.fetchJoinedGroups(this.context.matrixClient); + dis.dispatch(GroupActions.fetchJoinedGroups.bind(this.context.matrixClient)); }, onClick() { @@ -94,7 +94,7 @@ const TagPanel = React.createClass({ }, onTagTileEndDrag() { - TagOrderActions.commitTagOrdering(this.context.matrixClient); + dis.dispatch(TagOrderActions.commitTagOrdering(this.context.matrixClient)); }, render() { diff --git a/src/dispatcher.js b/src/dispatcher.js index be74dc856e..50585b969d 100644 --- a/src/dispatcher.js +++ b/src/dispatcher.js @@ -20,14 +20,24 @@ const flux = require("flux"); class MatrixDispatcher extends flux.Dispatcher { /** - * @param {Object} payload Required. The payload to dispatch. - * Must contain at least an 'action' key. + * @param {Object|function} payload Required. The payload to dispatch. + * If an Object, must contain at least an 'action' key. + * If a function, must have the signature (dispatch) => {...}. * @param {boolean=} sync Optional. Pass true to dispatch * synchronously. This is useful for anything triggering * an operation that the browser requires user interaction * for. */ dispatch(payload, sync) { + // Allow for asynchronous dispatching by accepting payloads that have the + // type `function (dispatch) {...}` + if (typeof payload === 'function') { + payload((action) => { + this.dispatch(action, sync); + }); + return; + } + if (sync) { super.dispatch(payload); } else {