-
Notifications
You must be signed in to change notification settings - Fork 228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Promises in actions #69
Comments
I'm pretty interested. Currently I'm using a plugin that I wrote to overwrite context.executeAction. I think it's mostly backwards compatible; I think the only case where it's not backwards compatible is when you're using the arguments object. I've been abusing co and generators, so feel free to ignore that part. From my actions I could just export co.wrap(action) instead to achieve the same goal. action-plugin.js var co = require('co'),
debug = require('debug'),
log = debug('ActionPlugin'),
isPromise = require('is-promise'),
isGeneratorFunction = require('is-generator-function')
module.exports = function ActionPlugin () {
return {
name: 'ActionPlugin',
plugContext
}
}
function plugContext (opts, context) {
context.executeAction = executeAction.bind(context)
return {
plugComponentContext,
plugActionContext
}
function plugActionContext (actionContext) {
actionContext.executeAction = context.executeAction
}
function plugComponentContext (componentContext) {
componentContext.executeAction = componentContextAction
}
function componentContextAction (action, payload) {
context.executeAction(action, payload).catch(err => {
context.executeAction(context._app._componentActionHandler, {err}, () => {})
})
}
}
function executeAction (action, payload={}, done) {
log(`Executing action ${action.displayName || action.name} with payload ${payload}`)
var promise
if (isGeneratorFunction(action)) {
promise = co(action(this.getActionContext(), payload))
} else {
promise = new Promise((resolve, reject) => {
var result = action(this.getActionContext(), payload, (e, r) => e ? reject(e) : resolve(r))
if (isPromise(result)) {
result.then(resolve, reject)
} else if (action.length < 3) {
resolve(result)
}
})
}
if (done)
promise.then(result => done(null, result)).catch(err => done(err))
return promise
} If it's a generator function, call the action with action context and payload, and pass it to co. If execute action got called with a third param, it'll also call done. One of the nice perk of using promises is that you don't have to worry about releasing zalgo. Would you be interested in a PR or did you have a different approach in mind? |
Yes, we'll absolutely take a PR. I'm not a big fan of adding |
Oh, definitely. Should it use the global Promise and assume that anyone that's using this will either polyfill it or replace it with their own preferred implementation? |
Good question. For now let's use Bluebird. Once we start using babel to compile Fluxible for ES6, we will be able to drop that dependency. |
Hi @cesarandreu we've migrated the docs over to this repo so if you want to add some documentation we can get this merged. |
👍 👍 👍 👍 =) |
I'll try to write up the docs tonight, thanks! :D |
IMHO, having callbacks and/or promises in actions is breaking Flux unidirectional data flow. According to a Facebook developer post:
Why Fluxible did this "correction"? |
@igorbt your observation is correct. In order to render server-side, we need to know when the page is ready to render. And we do that with callbacks. However, we do keep the flux flow with actions fired from the |
@igorbt There is a description of what @jedireza mentioned in the Components documentation. |
Thanks, @jedireza , @mridgway ! I understand now. It would be nice to see this explanation in the Actions documentation also. |
Haven't had a chance to update the docs yet. @igorbt: I think triggering actions inside of actions is fine as long as you make sure to wait for them in your parent action. |
@igorbt Good call out. I added more information to the actions doc. |
I'm just starting to explore Flux and Fluxible and the thing with calling another action from an action just doesn't feel right for me. I re-read the original Facebook Flux description but didn't find anything for or against this practice. I didn't find anywhere else some strong opinion about that. If Action1 calls Action2 and then dispatch Payload1, and in the same time Action2 dispatches Payload2, if feels like cascading updates. But Flux is trying to minimize that! |
While the actions may be asynchronous, there's nothing wrong with nearly-simultaneous dispatches--the stores should handle events and their payloads discretely, only being concerned with potentially waiting for other stores to handle an event first (using This isn't cascading, only asynchronous. It would be cascading if the stores were to trigger an action, or a component doing so without any user interaction. Does that clarify at all? (Disclaimer: I do not work on Fluxible) |
Furthermore, IMO it's very helpful for actions to set up other actions on intervals, for situations like polling. |
Updated my PR with docs! |
Awesome! I'll check it out soon. |
Support handling promises that are returned from actions instead of using callbacks.
The text was updated successfully, but these errors were encountered: