Closed tomkis closed 8 years ago
Please, we are still open to ideas / suggestions therefore feel free to use this issue.
Next has been merged to master and 1.3.1
has been released.
Have you considered async/await for the side-effects?
Async/await cannot handle all the aspects of the side effects and would make testing much more difficult, as has been laid out in redux-saga:
https://github.com/yelouafi/redux-saga/issues/7 http://yelouafi.github.io/redux-saga/docs/basics/DeclarativeEffects.html
Ah ha I see. But couldn't we use async/await instead of Promises (typically in effects.js
) while keeping sagas for their declarative awesomeness?
Yes, that is entirely possible, but I'm not sure there is much benefit. redux-saga's call
function is already Promise-aware:
// effects.js
// this function returns a promise
export const fetchRandomGif = () => fetch('/gif/random');
import { call } from 'redux-saga/effects';
import { fetchRandomGif } from './effects';
const response = call(fetchRandomGif);
import { fetchRandomGif } from './effects';
const response = await fetchRandomGif();
So as I see it, there is not much to be gained.
Also async/await (Async Functions) are mostly sugar on top of Promises. You can't use them without a Promise being created somewhere along the line.
So let me explain why async/await
can't be used for side-effects.
First of all, when you talk about side effects, you need to be more specific what you exactly mean by side effects, since you have mentioned async/await
I suspect that you meant API call, however there might potentially be side effects which are not asynchronous, for example logging. When you call console.log
it's impurity yet it's totally synchronous operation and would not benefit from async functions at all.
However, I am pretty much convinced that when you mentioned side effects, you actually meant long lived transactions. It's really confusing because even redux-saga
claims that it is:
An alternative side effect model for Redux apps
Which frankly, is a nonsense, because redux-saga
has nothing to do with side effects. Saga is pattern for Long Lived Transaction (LLT), which in Redux context means series of actions (which may or may not be asynchronous). Typically API call is LLT because it takes more than one action (Request, Response) in place and it lives in time (asynchronous).
async/await
is just a syntax sugar on top of Promises, you can just wait for Promise resolving, that's nice, it could help us with our Request <-> Response scenario, but what if our series of actions does not contain only two actions (Request, Response) but may be potentially infinitely long series? It's still transaction, right? It's still long lived, right?
async/await
helps you when you need to asynchronously wait for single value. Saga on the other hand can asynchronously wait for many values.
In other words the most trivial Saga definition is something which can accept infinite number of actions and dispatch infinite number of new actions, although it's not just map
it's more of flatMap
because reaction to one action, may potentially dispatch more than just one action.
And of course, there's also really nice abstraction and it's RxJS Subject ;-) (coming soon)
As many of you have already noticed, there's a
next
branch which is currently under heavy development.There're obviously many options we could go (especially for side effects model):
redux-loop
After many versions we've figured out by trial and error that we want to go the Generators way. We found
redux-loop
API a way too awkward for use and there's an alternative repo https://github.com/jarvisaoieong/redux-architecture which is using that.Using Sagas for side effects is nice alternative but composing Sagas is very difficult and there's no silver bullet implementation which would cover all the use cases, therefore Saga composition would have to be done in user land, which is frankly un-acceptable given the fact how difficult it is. Also sagas would ideally be un-aware of app state which discriminates Sagas' usefulness.
Using Generators for side effects definitely has its drawbacks:
yield*
effects when composing them (which some people consider advantage because it's explicit)We've decided to use Generators because of two reasons:
Goals for 1.x
next
branch now serves as development branch for 1.x, you can even install it using npm:Lightweight
We believe that modern application architecture should be based on solid Patterns, not thousand lines of Magic code therefore we'd like to keep
redux-elm
as lightweight as possible.Updater Abstraction and Side Effects
The idea is that we will provide
Updater
abstraction which can be converted into Generator friendly Reducer (we assume that https://github.com/salsita/redux-side-effects is being used).Pattern matching
Pattern Matching is essential part of this framework and we decided to give User an interface to provide any pattern matching implementation they need. We also provide 3 basic matchers which will serve in 90% of use cases.
Great documentation
Because redux-elm is about patterns, not implementation we are also working on very thorough documentation which should be great starting point for people who are not even experienced with redux or Elm.
Stay tuned!