
Show HN: Redux-Tiles – library to deal with verbosity of Redux - bloomca
https://github.com/Bloomca/redux-tiles
======
acemarke
I've looked at literally hundreds of Redux-related libraries and addons (and
listed anything that looks decently useful in my Redux addons catalog [0] ).
As part of that, I've seen dozens and and dozens of libraries that promised to
"reduce Redux boilerplate" \- usually functions for generating reducers based
on lookup tables rather than switch statements, but also other approaches as
well.

redux-tiles adds a bit more abstraction that I personally like, but it does
look useful and appears to maintain the overall spirit of Redux (as opposed to
many other "wrappers" that wind up trying to add OOP/class layers on top, or
obscure the fact that there's actions, reducers, and dispatching going on, per
some of the examples I listed in my blog post "The Tao of Redux, Part 2 -
Practice and Philosophy [1]).

I don't think I'd use this myself, but it seems like a reasonable approach to
"reducing boilerplate" overall. As always, it's up to you the Redux user to
decide how much abstraction you are comfortable with and want to use in your
own application.

Thanks to the author for putting this together and posting it.

[0] [https://github.com/markerikson/redux-ecosystem-
links](https://github.com/markerikson/redux-ecosystem-links)

[1] [http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-
tao...](http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-
part-2/)

~~~
bloomca
Thanks a lot for your feedback!

I've tried to keep the Redux spirit -- I completely agree about too much
abstraction, so I tried to build something much more simple, more basic thing.

Can you please describe which parts of abstractions you personally think are
too high here? I see it personally in `waitTiles` function to do SSR, and in
`createEntities` (while it is a pretty simple function, it looks like a
magic).

------
bloomca
Author here.

I worked with different domain models using Redux, and also different codebase
sizes, and it finally led me to this library.

Originally I was involved into building data layer for collections (e.g. how
Netflix shows list of series), and I was building a very complicated factory
to produce kind of the same thing -- actions, reducer and selectors, with
aggressive caching and normalizing.

Later I worked with less amount of entities, and more RPC style APIs (a lot of
interaction with user, which are pretty much bunch of requests, where you
track pending state, error and success -- think about reset password,
obtaining a token, etc). When you have not so many entities, normalizing
becomes not so necessary, but I have noticed couple of things which are
constantly used and were giving me pain points: \- tracking async code (e.g.
dispatching start, failure and success) \- universal approach to caching (each
action creator often had slightly different caching mechanism) \- nesting
results (e.g. put `terms` under `documents` reducer) \- because of verbosity I
personally tended to combine a lot of logic under a single action (so
sometimes several raw API requests were made from a single action, not just
dispatching other actions)

I have tried to address all of these issues here. The idea is pretty simple --
the library creates a so-called "tile" with everything: actions, reducer,
constants and selectors, allowing you to nest it in the state (so you can
easily separate let's say `user` part), and to nest results, universal
approach to caching (all async requests are aggressively cached, so if you
dispatch the same action, it will wait the already made request, and you can
safely await returned promise). Also, I expose function back, so it is much
easier to test it, in case you inject all dependencies to the middleware (I
personally like it, but seems that it is an anti-pattern).

And the last thing -- in case you instantiate middleware for each request on
the server side, you get back `waitTiles` function, which after dispatching
all needed actions will return you a promise, awaiting which will give you
fully resolved tiles. So, you can do dry run of the react render on the
server, wait for tiles, and then safely render again, knowing that everything
in `componentWillMount` under the render path will be fetched. This SSR part
still has few questionable parts, but I feel it is a good idea in general (I
want to write a post about possible scenarious, how to prefetch for SSR).

In case you have any questions, or just want to chat about different
approaches in reducing boilerplate size for Redux, I'd be glad to answer!

~~~
tarr11
Happy to see people trying to solve this problem. Can you talk about how this
compares to redux-saga?

~~~
bloomca
Thanks!

As @acemarke mentioned, they are really different (and there is nothing to
stop you from using them together, if you want -- tiles expose constants).

Even if you use redux-saga for all side effects, you would still have to write
some redux code, e.g. for `usedLoggedIn`, and even it is the easiest action
and reducer, it will take from you about 30 LoC. And usually we tend to group
reducer hanlders together, combining only the higher level (so, usually there
is only `user`, but only in case of big amount of actions we will separate
`userAuth`).

So, I've tried to make it as easy as possible to nest them (so you would use
type like `['user', 'auth']`), and to nest data under let's say ids. You don't
have to think about it -- there is just a little amount of magic under the
hood, which will nest it, merge data and combine reducers.

So, saga adresses side effects problem (especially when they are pretty
complicated, and depend on each other), while this library provides some sugar
on top of raw redux "ducks".

------
jdpigeon
Instead of creating another level of abstraction that a dev has to learn, how
about just creating smart IDE tools that help with Redux? E.g. noticing that
you're creating another action and automatically creating a statement in the
reducer

~~~
bloomca
Well, there are several problems here. While you are correct, that we don't
really have tools which will automatically create constants or generate a
reducer based on them, I personally don't think that it is a right direction.

First of all, there are too many tools around. So, unless it will be really
popular, it will be achievable only in couple of most-popuplar editors.
Secondly, there are some things which this approach won't solve -- for
instance, universal approach to caching and merging data in reducer (it can be
done via some helper functions, but you still will have a lot of boilerplate).

And also, some things are just hard to do -- for instance, combining reducers
with decent amount of granularity and complexity of maintaining it later.
Also, here I provide a way to do prefetching for server-side rendering, which
is another problem you'd have to solve.

------
graphememes
This is very nice, one of the major issues I have with the frameworks that are
coming out is the large amount of boilerplate. Nice work.

~~~
bloomca
Thanks a lot! I've tried my best to simplify typical use-case for Redux, which
should be enough for majority of users.

