Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've spend a lot of time evaluating Angular + Ionic, Vue and React. My goal is to rewrite my webapp as a SPA with complimentary mobile apps. Maximum code sharing would be nice. I'd like to add to the discussion what I learned and also add Vue for comparison.

Vue felt less intimidating at first, whereas React seemed to be overly complicated. Truth is, both are actually quite similar. The problem is that every single tutorial out there tells you: "React is only the V in MVC" (and so is Vue) but then goes ahead and implements all business logic in Components. I found it incredibly hard to learn about a sane (SPA?) software architecture. Some people throw in Redux and Vuex, but they actually only manage the state of the application. This is not where business logic goes.

Note: I haven't found a proper solution yet. Or let's call it this way: People dump their business logic in components and Redux and that works just fine to some degree, but they actually treat React more than the V in MVC. Just be aware.

React isn't that complicated, especially if you start out with functional stateless components, i. e. Components that only have a render function, props and no internal state. This helps to think about where state and logic should go and once you implement your first React components this way, you see that there's hardly any difference between Vue and React. Vue might let you even produce code that is more ugly than what you'd have produced with stateless components in React.

The beauty of React is that it forces you to think in a slightly different way. Vue seemed more accessible for a spaghetti code writer like I was (am?), but it wouldn't really challenge me in the same way like React does. Vue made me understand what reactive is all about, React helped me to think about state more clearly, especially if you want to slowly transition to functional programming.

Angular is often seen as a full application framework – and to some degree, that's true. But I suspect you'd gain a lot if you actually wrote your core application / business logic as if it wasn't part of Angular to make it more shareable. For example, if you want to go mobile with Angular, you could use Ionic, but it's not 100% compatible both ways and you must think of a way to structure your app so that certain parts (the model) is actually independent from the framework.

You could treat Angular more as a View-layer thing, which simply attaches a bunch of observers to your app state, which reduces the need for many APIs Angular offers and also reduces its complexity.

The OP wrote about dependency injection, which I found odd as a comparison metric. DI is a design pattern to solve a specific problem and React/Vue simply don't apply to this design pattern.

The main advantage of React over Vue and Angular is: React Native. Vue doesn't have anything close to it. Weex might be there one day, but right now, the docs are very incomplete, half in Chinese and I think it lacks a lot of components React Native already has. With Angular, the logical framework to build hybrid apps would be Ionic. Ionic is nice for specific cases: When your app is read-only!

This isn't about performance (it's solid on newer devices) – it's forms and input controls. This is where Ionic shows the ugly side of the underlying Webview: Mobile Safari simply sucks for things beyond a simple input field. Want to show a picker for the date that only shows 15 minute intervals? Good luck with that. An input field that allows decimal only? Your best bet is type=tel and neglect the decimal point separator. Or use the rather un-performant and ugly DatePicker that comes with Ionic.

But this is a thing where even average users notice a difference to native input controls. If your app is mostly read-only with nothing more than a button and a toggle as input controls, by all means, go with Ionic. Have a form in it? Make a minimal prototype with just this form and see for yourself how it plays out.

React is learn once, write everywhere, because you can't really share any component-related code between React and React Native. In React, you use HTML elements, in React Native, you use native elements.



> The beauty of React is that it forces you to think in a slightly different way. Vue seemed more accessible for a spaghetti code writer

This has been my experience too with React and Vuejs. React requires thorough planning beforehand to write good code. You need to plan the parent-children structure before you jump in. It's easy to write shitty code in react too if you jump in headfirst; resulting in the kind of "enterprise boilerplate" others are talking about in this thread. Personally, I am happy with React at the moment (and React Fiber let's you return an array of components, so no more wrapping your components around a span - yay!).


I haven't tried React but I felt the complete opposite with Vue. I've never written more beautiful front-end code than what I've done in Vue. Did you use .vue files? Did you use a proper state tree like Vuex?


Isnt Redux about using components to dispatch actions, and all the logic happens in the reducers for the store? So, the Model part is not inside the react view components which are just used for display. If you have uncontrolled components(React terminology for forms with extra data not handled by props), then form validation might require some processing in the components.


Partially, you're right. Some logic happen in reducers, but not all, because they must be pure. For example, you can't call new Date() in a reducer, because it's not pure.

Imagine you have a TodoList with Items that have: a priority and a createdDate. TodoList is always sorted by 'priority, created DESC'. There's also an email service that gives you a high-level overview of the TodoList like so:

  High Prio (3 items)
  Mid Prio (1 item)
  Low Prio (0 items)
  Total: 4 items, last created: 2017-04-07 11:38
This email is sent out whenever a new item is added.

So, your business logic is like this:

If a user creates a new TodoItem:

- You need to get the current date (unpure, so this must come from an action creator [1])

- You must update the "entity" of TodoList and sort and recalculate its summary

- This summary must be send out as an email

Or to sum it up: You have an action that triggers a bunch of totally unrelated side effects. This has nothing to do with the state of the View, which Redux manages. But it's still important business logic to this app.

The question now is: How do you manage that? Because this clearly must be outside of React and Redux. Some people just slap other libraries on top, but I never found a satisfactory explanation on how to implement such workflows "properly".

Too many tutorials are way too simple and gloss over these details.

[1]: http://stackoverflow.com/a/34135166/


It's 100% Redux ecosystem responsibility to perform the actions you want. I understand where you come from, as you perfectly described a procedure and it sounds natural to think that way. Redux and Event sourcing systems force you to decompose in 3 functions this procedure

- Action creator: the action creator newTodo() creates an action = {type: 'new', body = 'yo', date: new Date()}. This action creator can be colocated in the reducer file.

- Selectors: the summary is a denormalized view of the normalized state. Many would argue it is not a business logic but a display logic. Same for the sorting. A selector is a function that takes a part of the state as an input and return a new datastructure. Use reselect if you have perf concerns and want to persist it. It can be colocated code wise with the reducer file.

- Saga: for the side effects of sending an email, we use Redux Saga for ol' REST based endpoints. Those can be colocated code wise with the reducer file.

So yes you have 4 functions for your todo business logic: some action creators, some selectors, some sagas and the reducer. They can all be in the same file. It takes a bit of practice to figure out what is the right cut-off point. But all in all, interns and old farts like me all grasped it way more easily than Angular 1 scope concept for a more rewarding value.


This is helpful, thank you. One note:

> Selectors: the summary is a denormalized view of the normalized state. Many would argue it is not a business logic but a display logic. Same for the sorting.

Yes, I read about that before. Don't put in the store what can be computed. But in my case, this isn't used in a view, but in a separate "object" that can be shared with others without sharing the underlying data. So, while the report attributes are all computed, they must be stored somewhere for later individual retrieval.

Anyways, could you please clarify this:

> So yes you have 4 functions for your todo business logic

Where do I bundle these 4 functions so that they're called always in the same order?

> It takes a bit of practice to figure out what is the right cut-off point.

Yes, that's my struggle right now ;)


The common solution seems to be using redux-thunk to shoehorn all of this business logic into the action creators. I think that's an absolutely terrible idea. IMO redux-thunk muddies up the terms "dispatch" and "action creator" and essentially creates a huge noob trap where new programmers don't even know what an action creator is anymore and they use the wrong terminology for everything.

Having said that, I think the thunk pattern is a fantastic solution. The two things the business logic functions need to do their job are dispatch, and the state, and the way redux-thunk does it with dependency injection makes your business logic functions very easy to test.

If somebody can come up with a solution with the same principle but without the absolutely moronic overloading of terms that people somehow find acceptable about redux-thunk, then they'll be onto a winner.


Thanks for the input. This reflects what my problem is as a beginner with all this stuff: Where do I actually put everything? There's no universal answer of course, but this is why I (and certainly many others) feel intimidated by the JS ecosystem as a whole.


The Redux FAQ has a related entry: http://redux.js.org/docs/faq/CodeStructure.html#structure-bu... .

Out of curiosity, could you give me some examples of what you view as "business logic", and what troubles you're having placing that into a React+Redux app?

(Also worth noting that BigJono and I debated the merits of redux-thunk in another recent thread: https://news.ycombinator.com/item?id=13987613 ).


Thanks for the link. Business logic, to me, is: 1. Make sure that domain rules are enforced and keep data consistent. 2. For every use case, always trigger the same sequence of actions (behavior and side effects).

Imagine a fitness app where you can enter workouts and how much water you drank. You may enter only one workout per day (rule) and you cannot enter more than 1 gallon of water (rule). When you add a workout (behavior & side effects): the weather API is called and the current weather is added to the workout, the workout is stored in the DB, some calculated statistics are updated, your public "progress report card" is updated, you get a "good job!" push notification.

In my PHP OOP spaghetti approach, I might create an AddWorkoutCommand that executes() these actions by calling a bunch of other functions in other objects and trigger an event for optional listeners/actions. With Redux, not everything is in the same store (or in the store at all) and I don't even know where to start. It feels like this doesn't have anything to do with Redux, because it's partially not even state/view-related.

Maybe I'm overthinking this, but I do have a hard time finding a good tutorial that shows how to work with behavior and rules that goes beyond "add this item to the todo array".


I could picture handling that kind of thing several different ways.

First, the UI may want to prevent the user from being able to hit "Add" or something if a workout already exists for that day. The component could use a selector to determine if there's an existing workout, return the flag in `mapState`, and disable buttons or forms appropriately.

Second, the action creation logic could decide to not actually dispatch an `ADD_WORKOUT` action by inspecting the current state and only dispatching the action if allowed. (I have some relevant examples of redux-thunk use cases like this at [0]).

Third, the action could get always dispatched, but the reducer could make the decision whether to actually insert the proposed workout into state.

Regarding the side effects, this is a good use case for "sagas". Dispatch an `ADD_WORKOUT` action that triggers a saga, but is ignored by the reducers. The root saga kicks off a child saga when it sees that action. The workout saga could then decide whether it needs to actually add the workout based on state, dispatch another action that actually updates the state, make the AJAX call for weather and persist it to the server, and trigger a push notification. (You can do same thing in a thunk, it just would need explicit promise usage rather than the synchronous-looking code of a generator-based saga.)

Lastly, this isn't a direct answer to your question, but you may be interested in some of the more in-depth Redux tutorials I've collected. They're in the 'Redux Tutorials#Project-Based Tutorials" section of my links list [1]. In particular, I recommend "Building a Simple CRUD App with Redux" [2], and my own "Practical Redux" series [3].

Hopefully this gives you some ideas. I'd also invite you to come ask questions in the Reactiflux chat channels on Discord. The invite link is at https://www.reactiflux.com . Great place to hang out, learn, and discuss React + related topics.

[0] https://gist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e...

[1] https://github.com/markerikson/react-redux-links/blob/master...

[2] http://www.thegreatcodeadventure.com/building-a-simple-crud-...

[3] http://blog.isquaredsoftware.com/series/practical-redux/


Just to be clear, I wasn't debating the merits of thunks, I love the pattern. I was just questioning the decision to use redux middleware to implement them. Redux-thunk action creators do not return an action. It's a misnomer to call them action creators.


Redux reducers don't manage the state of the view, but of the app. Redux state is the "M" in MVC; Redux action creators are the "C".

The view's job is to display the current state, translating it into something presentable. Views call action creators to request changes to the state, or to report events that action creators should use to make changes to the state. Action creators implement business logic.

Edit: To be clear, this doesn't mean you have to do logic in action creators. You can keep action creators "pure" (not thunked), and instead have a business logic layer that mediated between view and action dispatching. Saga is one way of doing this. Redux doesn't mandate anything specific.

Reducers are a way to serialize the state so that all state transitions happen as a strictly sequential chain of modifications. This is done to prevent the spaghetti mess you get when (as in traditional MVC systems like Cocoa) everyone is allowed modify the state directly, and views merely observe state. By flowing state through a single bottleneck, there's only one moment when the UI needs to transition to a new state. With observation-based systems, it's completely unpredictable and certainly not reversible.

React components do of course also have something called "state", but you have to think of that as the UI state, i.e. things needed to manage the view, such as whether a dropdown is open or what the current text of an input is.

There's also the temptation to put UI-specific state in Redux. This is perfectly normal, and even desirable. The "M" in MVC is not some abstract ivory-tower notion that there exists some world state that's entirely independent of the view. The state serves the view; whatever the view needs must be provided by the state.


  "The main advantage of React over Vue and Angular is: React Native. Vue doesn't have anything close to it."
Have you tried Quasar? (http://quasar-framework.org/) We're using it right now for a customer project and I'm very happy so far. Performance feels better than Ionic2.


I haven't tried it, because the components don't look native. Buttons with text that have a shadow? What on earth is that? It looks less polished than Ionic and suffers the same problems of all Cordova-based hybrid apps: No native input controls. For me, this is a dealbreaker.


Cordova is all about plugins. You can use a native datepicker plugin for example.

If you need native functionality, use a plugin. (there's probably one already there, but maybe you need to write a tiny bit of native code).

I guess that's the whole point of hybrid that people don't understand - it's a hybrid, and you get to choose the best of both, making the trade offs you need to make for the best result.

Not ideal for every app/budget, but I think people just don't get this part - use the native plugins if you need them! :)

Ship fast, and slowly replace all the bits with native (if you need to). [fast|cheap|good] pick two! (then the third).


So, the idea of Ionic/Cordova is: You can release an app without writing native code. Your suggestions certainly work, but they bring up questions:

- How do I write the native code you mentioned?

- How do I plugin the native datepicker in Ionic?

- How do I deal with different native plugins for iOS and Android?

I bet there are solutions for all of these problems, but then again, I might just want to consider React Native, because Ionic doesn't bring any more benefits over React Native.

With Hybrid, it's all a compromise, and it might be worth it. That's not my point. My point is: Don't use Ionic/web-based hybrid, if native input controls play an important part in your app. It might simply not be worth it, because there are better tools to achieve the same outcome.


The datepicker native input plugin exists, so it's just installing it. Then you get a JS api for it.

If it doesn't exist somewhere in the thousands of plugins available, you'll have to make it yourself. The other thing that happens, is perhaps a plugin is only available for Android. Maybe there's another one with a slightly different JS api for iOS... or none.

I've also done emscripten compiled C++ mixed in there. Which replaced various native apps. Since it was mostly OpenGL anyway... the few controls were easily implemented in JS/Html.

Anyway... just trying to share some options. Lots of native cordova plugins available (which I guess is it's main point). I really don't care what other people do... and somehow got drawn in to this discussion again!


Thanks for the suggestions. While trying Ionic, I didn't install Cordova plugins to fine-tune input control. I will give it another shot.


I mostly agree, just a silly nitpick: Fast usually means cheap, especially if you are talking about software engineering. So I'd say the choice is between "fast & cheap" and good.


Really nicely put.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: