joshburgess / redux-most

Most.js based middleware for Redux. Handle async actions with monadic streams & reactive programming.
https://www.npmjs.com/package/redux-most
MIT License
139 stars 14 forks source link

Document 'select' behavior #13

Closed vlad-zhukov closed 7 years ago

vlad-zhukov commented 7 years ago

Calling select (and I assume selectAny as well) returns a stream that can be chained further as follows:

select(EPIC_ACTION, action$)
  .concatMap(...)
  1. Should this behavior be mentioned in the readme?
  2. Shouldn't it be preferred to $action.thru(select(EPIC_ACTION))? It looks cleaner and I suppose it's a bit faster since less stuff happens.

Thoughts?

joshburgess commented 7 years ago

@Vlad-Zhukov

  1. I mention that select and selectAny are just convenience features for filtering, so it's somewhat implied that they would return a stream (because they're really just using Most's .filter() internally). I'm okay with you adding a little extra to the README if you want to though.

  2. I actually prefer using the functional style where streams get passed in last. I think which style is cleaner depends on the background knowledge of the user. The reason I prefer the functional style is because it opens up the possibility of creating reusable functions via currying & partial application. This is analogous to how lodash/fp and ramda work, only with streams instead of arrays. Take a look at how I use currying & partial application when working with Ramda & Mori in this repo if you're interested in seeing some examples: inferno-most-fp-demo

Having said that, some people are used to and prefer chaining. So, I think it's fine to just leave it up to the user. However, an interesting thing that is happening right now with mostjs/core is that they are switching to making all Most operators auto-curried (like Lodash/fp and Ramda), so that we won't even need to use a curry function ourselves when working with Most & making reusable functions that accept arguments getting passed in one at a time anymore. I think this is a good reason to try out & embrace the more functional style over chaining.

vlad-zhukov commented 7 years ago

I agree that the functional style is practically better but I was talking about the chainable style specifically, and how it is used in the readme and the example app.

joshburgess commented 7 years ago

I show both styles in the README & example specifically because more people are familiar with the chaining style, and I want to encourage using the functional style. There are still many people out there who have used lodash for years who don't even know that lodash/fp exists and haven't heard of ramda.

vlad-zhukov commented 7 years ago

We've got a little misunderstanding here. My question is: why do

$action.thru(select(EPIC_ACTION))
  .map(...)

when you can do

select(EPIC_ACTION, action$)
  .map(...)

Sorry for the confusion, I have nothing against functional style and in fact use it myself. I was just wondering why you use .thru in docs.

joshburgess commented 7 years ago

Ohhh, I see. The reason is because the 2nd style you've shown is sort of mixing both the functional style & the chaining (aka "fluent") style together, whereas the 1st is consistently using the chaining style. It's basically as close as I could get to redux-observable's .ofType() method, where they just chain directly off of the action itself to do the filtering. They actually extended the observable class to add extension methods, like that one (and others), but I didn't want to do that, because I'm not a big fan of using ES6 classes and inheritance in that way. I wanted to only use standard Most.js streams and just add any extra utility functionality through standalone functions instead.

joshburgess commented 7 years ago

I'm going to close this for now, but if you'd like to add a small comment to the README showing that you can mix and match the fluent style & functional style, feel free to open a PR for it. Also, I just renamed selectAny to selectArray.