Hacker News new | ask | show | jobs
by whitefish 3340 days ago
Those who think React + ReactRouter + Redux is too complex -- you're right. But there is an easier way to use React: MVC. React is the V in MVC.

https://github.com/Rajeev-K/mvc-router

Note that using MVC does not imply 2-way binding!

3 comments

React is very usable without Redux. I'm not sure how they became bound so tightly together.

I keep seeing this pattern of redux as a page-level data store, whereby on each page load you pull your data from rest APIs, put it in that page's part of the data store, to be modified with that page's reducers, triggered by that page's action creators. Then it's all hooked up to one single page-level connected component which passes all the state down to other components as props anyway, making it functionally identical to just using the React state in that page component.

The justification for this is usually either "Now you can make your page components pure functional components!" (whooptee-do) or "Redux scales better" (citation needed). Pretty thin.

I agree that "only use functional components" is a heavily over-opinionated approach (I actually tweeted a counter-statement to that recently: https://twitter.com/acemarke/status/855192917727735808 ).

There _are_ definitely a number of benefits to using Redux in a React app. I actually co-authored an article that discusses some of them: https://www.fullstackreact.com/articles/redux-with-mark-erik... . TL;DR: time-travel debugging and better hot reloading for development, easier management of data that needs to be used in multiple places throughout the component tree, and all the niceties of having centralized state (logging, state persistence, issue reporting, etc).

I'm beginning to think there'd be a way to make Redux a helluva lot clearer by sticking everything in a class with a well-defined interface (but: ewwwww, classes, impure, burn the heretic!). Keep all the definitions for an actioncreator, event (action), and its reducer in one place. Hand the whole class to Redux and forget about it. Can compose actions/reducers inside those classes if you want/need to, so no loss there.

The pile o' reducers thing just isn't a very useful way to organize code IMO, and having everything split over several files makes following what's happening a PITA (especially without something like Typescript to let your tools give you the information you need, rather than having to keep it in your head or go look it up manually).

Redux feels... not over-engineered, exactly, but maybe mis-engineered.

... or we could just cut out the middleman and go all Actor model on this problem. Just sayin'. (yes, I know there are actor-model libs for React out there, but frankly the churn-related breakage and confusion in the most popular tools is so bad I'm afraid to step outside the mainstream, where it's probably even worse—plus we don't get to choose our own libs/patterns all of the time)

>I'm beginning to think there'd be a way to make Redux a helluva lot clearer by sticking everything in a class with a well-defined interface (but: ewwwww, classes, impure, burn the heretic!).

I thought the same thing. That's why I started using VueJS with Vuex. Vuex accomplishes the same things as redux in a much more manageable and centralized manner. Plus, you don't have to worry about connecting your components to the store through `react-redux` or whatever. With Vue and Vuex, you just pass the store object to the root view component and it's available in every single child component via `this.$store`. You can then `dispatch` actions which perform `commits` which call `mutations` which update the state. Then, in your component you create a computed property that uses a `getter` to return the piece of application state you want. It's a really simple top down data flow and everything is namespaced. It's so absurdly simple and easy that I don't understand why redux doesn't take a page from vuex's book.

I really should write a Vue + Vuex tutorial for beginners as I'm super happy with the way it works.

You don't even need a class, but either way, this is essentially how Elm works.

There are very different semantics at work there though. Elm is Fractal, Redux is not. Each have tradeoffs. Some stuff gets simpler, some stuff gets harder (the 1:1:1 scenario where you have a component, an action, and a reducer to achieve 1 thing gets easier. The N to N to N scenario where a reducer can handle things from all over the system, gets harder).

It's not misengineered, its just optimized to make a different set of problems easier at the cost of making others harder.

There's already a whole bunch of "define Redux action creators and reducers as classes" libraries out there. I've added the ones I've seen to my Redux addons catalog, in the "Variations" category: https://github.com/markerikson/redux-ecosystem-links/blob/ma... (which is where I list stuff that builds on Redux, but takes it in a "non-idiomatic" direction).

There's definitely several different schools of thought about how to organize and structure Redux-based code. Dan is a big fan of the "small independent slice reducers responding separately to the same action" approach. Others prefer to see all possible state changes for a given action in one place. And yes, while the intended use of Redux is based on functional programming, there's also those who prefer putting OOP layers on top.

I'm actually working on a blog post that will try to clarify and discuss what actual technical limitations Redux requires of you, vs how you are _encouraged_ to use Redux, vs how it's _possible_ to use Redux. Been busy with other stuff, but hoping to make progress on that post this week. If you're interested, keep an eye on my blog at http://blog.isquaredsoftware.com .

You may also be interested in an issue I recently opened to discuss possible future improvements and "ease-of-use" layers that could be built on top of the Redux core: https://github.com/reactjs/redux/issues/2295 .

Finally, I'm always happy to chat about Redux (and React) over in the Reactiflux chat channels on Discord. The invite link is at https://www.reactiflux.com . Feel free to drop by and ping me.

> React is very usable without Redux. I'm not sure how they became bound so tightly together

Because that's what easily-excited developers see on HN and Twitter, so they think they have to use it.

Without ragging on developers that do this, I actually think it's a very serious problem. I frequent the #react irc channel a lot, and almost every beginner comes in with the same sentence: "I really like the way ___ does ___, where do I start?" (or some variation of)

If you're using the words "like" or "cool" to describe your latest dependency then that's a serious red flag. These libraries exist to solve problems, if you can't describe the problem you're trying to solve with one of them then you shouldn't be using it.

I don't understand Redux, I have almost 20 years of coding (I probably suck at it though). I once asked a developer at an interview if he could explain the redux stuff he had used in an assignment. He couldn't and I really tried to understand all the boilerplate and inner designs of the library, but I found it really hard to get into. Mobx though, 2 minutes and you get it AND you get more efficient in building complex UI:s.
You started on the wrong foot. Learning from someone who cannot explain his own code is not the right context to learn any tech.

Redux is a modern implementation of CQRS/Event sourcing, a design pattern that existed before you even started coding. Many developers, in different languages, learned it and used it (if you want to implement an undo stack for instance, there is not a lot of other solutions around). Trust yourself and your intelligence. Our devs learn it in about 3h with our training program and get a return on investment in about a week.

MobX is nice and if it fits you, go for it. If you are a hands-on kind of guy, you may discover the limits of MobX by using it, and from the trenches finally understand why Redux, and why does it need 3 objects (a store, a reducer, an action).

I'd be happy to answer any questions you might have about Redux if you'd like. The Reactiflux chat channels on Discord are a great place to hang out, ask questions, and learn. The invite link is at https://www.reactiflux.com . Feel free to drop by and ping me.

Also, I keep a big list of links to high-quality tutorials and articles on React, Redux, and related topics, at https://github.com/markerikson/react-redux-links . Specifically intended to be a great starting point for anyone trying to learn the ecosystem, as well as a solid source of good info on more advanced topics. It includes links for learning core Javascript (ES5), modern Javascript (ES6+), React, and much more. I also published an "Intro to React (and Redux)" presentation at http://blog.isquaredsoftware.com/2017/02/presentation-react-... , which is a good overview of the basic concepts for both React and Redux.

I learned the unidirectional data flow pattern with flux before redux and redux makes flux look like war & peace! :P

The no frills way I like to think about redux is your rendered page is the result of a function operating on a state object. Changes to the state object trigger re-renders. There's obviously some subtleties in there and complex use cases, but that's the basic gist.

It's two event/message dispatchers slapped together. One for "reducers" that take an event/message and apply it to state, one that automagically applies the resulting state-change event to do stuff to your views. You mostly don't need to worry about the second one.

As far as I can tell, that's it.

For bad reasons they've decided to stick with the terrible "action" name for their events/messages, which has made the whole thing super confusing (turning "actionCreator" into "eventCreator" immediately makes things much clearer, for instance).

There's also a ton of convention/process taught on top of it for some reason that's IMO not that great, and makes it really hard to see what's actually part of Redux and what's cruft on top of it that you can skip/modify. Redux-as-typically-presented is mostly you doing stuff to follow a (kinda painful) pattern, not the Redux library helping you do stuff.

[EDIT] I'd add that the communication pattern of the docs and various attempts to help people understand Redux seems to largely be "oh, you didn't get it? Let me say the same thing again but louder". Which is why there's SO MUCH documentation and chatter for something fairly simple, I think. Which just compounds the problem.

A lot of the naming of stuff goes back to Redux's Flux heritage. The Flux architecture labeled those objects as "actions", so Redux (since it was intended as a "Flux implementation") kept that naming.

You are right that the majority of usage is really at the user level, than the library level. I'm actually working on a blog post that will try to clarify and discuss what actual technical limitations Redux requires of you, vs how you are _encouraged_ to use Redux, vs how it's _possible_ to use Redux. Been busy with other stuff, but hoping to make progress on that post this week. If you're interested, keep an eye on my blog at http://blog.isquaredsoftware.com .

If you have concerns with the docs, I'd appreciate any specific suggestions or ideas you might have for improving them. Docs issues and PRs are absolutely welcome, from you or anyone else who wants to help improve them.

Finally, I recently opened up an issue to discuss possible future improvements and "ease-of-use" layers that could be built on top of the Redux core: https://github.com/reactjs/redux/issues/2295 . Would be happy for any feedback you could offer.

(edit: just noted I replied to you a couple different times in this thread, and repeated myself a bit. Offer of discussion absolutely still stands :) )

This is my experience as well. The largest struggle I have with Redux is understanding where things belong. Where do ajax calls go? Should I use redux-thunk? That feels like an anti-pattern to me. Redux-saga is interesting, but it's going to be really tough for unfamiliar devs to understand generators with infinite loops. I also don't feel like writing an infinite loop every time I want to perform a simple fetch. With mobx, shared code goes in a class, it doesn't matter if it's async or not, and observable properties get a decorator.
Dan wrote a couple great answers on SO that discuss why async behavior in Redux is normally done via middleware such as `redux-thunk` and `redux-saga` - see http://stackoverflow.com/a/35415559/62937 and http://stackoverflow.com/a/34599594/62937 .

As a short version: you _can_ put your async logic right into components, but it's nicer to move that logic outside components for reusability. Middleware have access to `dispatch` and `getState`, so they act as a loophole that enables you to perform async work and then interact with the store.

My own take is that `redux-thunk` is sort of the "bare minimum" approach to async behavior, as it allows you to do stuff with promises and async functions, or complex synchronous logic. Sagas are useful for complex async workflows, and there's also some popular observable-based side effects addons as well. Ultimately, the approach you use is up to you.

If you'd like more info on what good Redux code structure looks like, you may want to read through the "Redux Architecture" and "Redux Techniques" section of my React/Redux links list at https://github.com/markerikson/react-redux-links/blob/master... . Also happy to answer any questions you might have.

Or you could just cut out the middle steps and make the switch all the way over to Elm ;)
I recently completed two projects, one in Elm and one in React. Elm was a lot more fun. JSX in particular felt very unwieldy compared to the Html package in Elm. Being able to write everything in a neat functional language was a nice experience for me.