composable / higher order effects
See original GitHub issueSometimes multiple actions need to be chained to make a thing happen. For example: logging a user out means that:
- local storage credentials must be wiped
- all individual state values must be wiped
- tokens must be invalidated on the server
- when all that’s done, navigate to a new view
redux
has a concept of redux-saga
to handle this. It’s basically a way of combining multiple actions into a higher-order flow. Pretty damn interesting, and definitely useful. Actually I built exactly this stuff last year in the form of barracks.
So umm, I think probably the right way of dealing with this is to allow for callbacks from within effects
so they can be composed into higher order effects
(which we can then refer to as sagas
, although they’d simply be a pattern).
An example:
const http = require('choo/http')
app.model({
effects: {
binbaz: (state, action, send) => {
http.get('/foo/bar', function (err, res, body) {
if (err) return send('oh no!', err)
send()
})
},
foobar: (state, action, send) => {
send('binbaz', function () {
console.log('hello world!')
send()
})
}
}
})
I feel like send()
loses a bit of its semantic meaning here, perhaps an extra, optional cb()
argument should be added? Anyway, I hope the idea comes across. I feel like the idea is there, but I’m overlooking quirks and the consumer-facing API isn’t quite where it could be - suggestions are heaps welcome! - Cheers ✨
See Also
Issue Analytics
- State:
- Created 7 years ago
- Comments:11 (6 by maintainers)
Top GitHub Comments
👍 on having a migration guide. You could just have these be covered in the
async
section of the user guide. tbh the fact that you needed to add a middleware to support async with redux was a code smell. I also really like that this approach does not ram promises down my throat. I would be very happy to see that be an add-on if ever introduced.I’ve been giving this a lot of thought and I think that what’s needed is a callback in
effects
to signify it’s done executing and handle control back to the function that initiated it:Obv in a real world scenario we’d use proper async abstractions such as map-limit or pull-stream, but I hope the point comes across. Does this make sense?