Closed josepot closed 6 years ago
Hey @josepot, sorry for taking a bit long having a look at this, here are my thoughts
First, answering your specific questions:
rereducer
. However, we could work that out, and even made a version where we could apply a type guard on a discriminated union of Actions. What I would say is let's try to make something practical first, then see how does it meet with TS declarations, then we can see if it's worth making types less strict, breaking down the function into two, or whateverswitch
function (which we will have to find a better name... switch is a JS keyword, and switchReducers is not switching reducers...) is the main one of this library anymore.... If you only use the current default export, you can still make non-pointfree subreducers that hang from that rereducer. So you're still getting some added value, because you don't need to type all the boilerplate for a reducer with all the switch cases + initial value + break;
s, plus the switch cases can be as complex as you need (as they can be functions that take the state and the action), but still - it does look like it's just another function in this set of helper functions. The question is: is there a good chunk of consumers who will only use this method? But again - maybe it's just worth keeping it there for backwards compatibility.Now, to other points I wanted to mention:
addReducer
is not just sugar for 'subReducer', I wouldn't consider them being merged anyway: Conceptually they were two very different functions, each one does its own thing.getAction
reducer that returns the action? This way these methods can be composed. Or maybe it's better to keep everything a reducer?
I'm going to use the issue to try to spit out some thoughts that I've been having... Sorry if this looks more like a rant than an issue.
So, the reason I started
rereducer
is because I find the typical redux reducers quite verbose and imperative, and I wanted to be able to break them down into smaller functions and then "glue" them together with a reducer enhancer.I thought that a basic way to split reducer functions was to separate the "case" from the "transformation". By "case" I mean checking whether the a new state has to be returned for the given action with the current state, and by "transformation" I mean the function that generates the new state. That's basically what
rereducer
helps us do.But at the end of the day
rereducer
is just a reducer-enhancer and as such it can be composed and/or used with other enhancers.Since I started using it I found myself creating other reducer-enhancers that I re-use pretty often. I also happen to use Ramda in
almostall my projects. So, by combiningramda
withrereducer
and those enhancers, I was able to write my redux reducers as a composition of many small point-free functions. Which may look weird for those not use to that (everyone else in this planet), but it has some benefits... Like identifying common patterns, so that I can create new enhancers for those :see_no_evil: :joy: (Just kidding, I will explain those advantages in detail in a blog post). A silly example of what I'm talking about.To the point: I'm considering re-purposing this library to make it become a collection of reducer-enhancers and helper-reducers.
It goes without saying that the current default function will still exist. What I'm not sure though, is whether in v3 we should still have a default function. I think that if rereducer becomes a collection of enhancers and helper-reducers, then perhaps the current default function should be called something like
switchReducers
or justswitch
?We could also keep it as a default function and as a named function, but that's a bit weird.
These are some of the other enhancers that I would like to add:
subReducer
(alt names:innerReducer
,scopedReducer
), example of usage:The first parameter is the
getter
and it can take the following types of arguments:string
: the name of the prop that has to be updated.The second parameter is the transformation reducer, scoped to the value that's being transformed.
addReducer
(alt name:assocReducer
), example of use:The first parameter works the same as the first parameter ofThe first parameter is a reducer that's a getter for thesubReducer
.key
of the value that will be assigned to the current state, just for consistency with the rest of the API it can also be a static value. The second parameter can be:Ok, yes,addReducer
is actually just "sugar" for "subReducer"... So, perhaps the 2 of them could be merged into 1. Meaning that we could get rid ofaddReducer
, and just make it an special case for when the second parameter ofsubReducer
receives an object or a primitive instead of a function... It's an option, and perhaps it's the best one. The only thing that makes me hesitant about that is the crazy amount of overloads that enhancer will end up having... But I think it's reasonable.It is not true at all that
addReducer
is just sugar forsubReducer
, that was a brain-fart.deleteReducer
(alt name:dissocReducer
). ExamplesOther enhancers that I would like to add, but that I won't explain into detail now (although you can get an idea), are:
concatReducer
popReducer
shiftReducer
combineDependantReducers
(this one deserves a separate discussion, and perhaps doesn't belong in here)Finally, I would also like to add 2 helper reducers:
isType
:payload
:const getPayloadText = payload('text'); getPayloadText(null, {type: 'FOO', payload: {text: 'fooText'}}); // => 'fooText'
const getPayloadFooId = payload('foo', 'id'); getPayloadFooId(null, {type: 'FOO', payload: {foo: {id: 'fooId'}}}); // => 'fooId'