Understanding redux-saga: From action creators to sagas(blog.logrocket.com)
blog.logrocket.com
Understanding redux-saga: From action creators to sagas
https://blog.logrocket.com/understanding-redux-saga-from-action-creators-to-sagas-2587298b5e71
11 comments
This fails to demonstrate any benefit. The end result, ease of implementation, action flow and performance are the same, with a couple extra abstractions in the middle. What does it achieve?
Redux-saga is overkill for simpler use cases (like basic API requests), but it's a life saver for taming heavily asynchronous workflows. I used it for dealing with crypto operations in EnvKey[1], and I really couldn't have gotten by without it. It makes chains of asynchronously interdependent actions almost as easy to reason about as normal synchronous code. There's a learning curve, but it does pay off in projects of sufficient complexity. At this point, I'd say it's my favorite library in the whole Redux ecosystem.
1 - https://www.envkey.com
1 - https://www.envkey.com
One key advantage of redux-saga is testability-- since sagas are essentially functions with their arguments passed in by the saga middleware, it is easy to inject mocked dependencies in a test environment.
It isn't hard to create easily testable redux actions using redux-thunk. When you configure the redux store you can use `thunk.withExtraArgument` to provide a service object to your actions, so you can write something like this:
const getDog = dogId => (dispatch, getState, { DogApi }) => {
dispatch(fetchingDog(dogId))
DogApi.getDogById(dogId, (err, dog) => {
dispatch(err ? dogFetchError(err) : fetchedDog(dog))
})
}
...
dispatch(getDog(123))Strongly agree having worked on projects that use redux-saga. More difficult to debug, more magic, no real benefits. I would love to be proven wrong however.
How large were the projects? Was there a high level of concurrency? redux-saga is definitely an example of over-engineering unless you fully understand its benefits (which are many, depending on context).
The main project I worked on that had redux saga was a very simple concept that I think would have had no problem without it. There was no complex behavior. I think your insight about over-engineering would definitely apply here. It was apart of the basic boilerplate of the front-end from the beginning in this project despite not having a reason to use it. This seems to be a common theme based on the react developers I have been in contact with.
Agreed, not sure what this gives over redux-promise-middleware, which lets you write things like:
function myAction () {
return {
type: 'MY_ACTION',
payload: someApiCall(),
}
}
And that will dispatch `MY_ACTION_PENDING`, then `MY_ACTION_FULFILLED` or `MY_ACTION_REJECTED`. Soon you'll be able to write your payload as an `async function`: function myAction () {
return {
type: 'MY_ACTION',
async payload (dispatch) {
const apiResult = await someApiCall()
dispatch(anotherActionCauseWhyNot(apiResult))
return apiResult
}
}
}
I'm sure there's more to redux-saga, but this article doesn't do a great job of presenting that.The library helps manage complex, concurrent in-flight workflows. Games are a great example of this, or something like a flight booking app that communicates with many different processes and servers and you need to ensure that fine-grained control is maintained at all times.
Another benefit of redux-saga not mentioned here is the ability to build stateful sagas. For example, something like a game loop can be encoded in a saga like this:
export default function* playGame({ getState, selectors }) { yield take(GAME_READY);
export default function* playGame({ getState, selectors }) { yield take(GAME_READY);
const refreshDelay = 1000 / FPS;
while (true) {
yield take(START_GAME_PLAY);
while (true) {
const {
gameState: {
speed,
isPlaying,
gameTime,
},
} = getState();
if (!isPlaying) {
// game play has stopped
break;
}
const timeDelta = refreshDelay * speed;
yield put(setGameTime(gameTime + timeDelta));
// sleep
yield call(delay, refreshDelay);
}
}
}redux-sagas are awesome. If you have a complicated web app (and most apps aren't) then it's a godsend. It really simplifies a lot of the business logic. You do have to be careful about performance though.