React/Redux Links: a curated list of tutorials for React, Redux, ES6, and more
github.com
github.com
Does one really need to read dozens of articles as a starting point to get into this stack? Or is the learning curve to the latest and greatest patterns actually significant? (Note: I'm not trying to shoot this down, I'm legitimately curious about the perspective of those who are starting to learn)
That being said, I'm still trying to figure out how to build a few parts of my app the "Redux" way and I feel like it's making it way more complex instead of simplifying it.
For instance, in most redux trivial examples, the store and the views are directly mapped. I.e. 4 tasks in the store = 4 tasks on the screen. But in practice, sometimes the view evolves differently. Maybe we don't want to show the new task because it would confuse the user and it would be better instead to show a "Show new changes" button.
But then, you're now duplicating the state of the app. Since redux only tells you when the AppState has changed, how do you figure out how to update that UIView strictly from the AppState()? Yes, you can regenerate UIState every time but you need to store additional stuff in the AppState to be able to do that (For instance, was the "Show Change" button shown or not?). Also, regenerating a very big object on every change in the store can truly degrade performances.
There are some libraries (Such as reselect), but it's essentially the same thing, your view object needs to be recreated from scratch when there's a relevant change in the AppState.
One possible solution is to have components listen to the store actions and they would have their own reducer to update the "UIState" accordingly. But then it's moving away from the current "Redux Way".
That's just one example of how it can get complex even though the redux idea (One store, one reducer) is simple.
By the way, anyone knows how to solve the issue I just mentioned? :)
For the past year at work I've been working with re-frame (clojurescript) which has roughly the same model. The main difference is on the reducer side: components dispatch an event vector directly with the event keyword (action) as first element, then instead of a reducer that switches on action strings, we register a set of event handlers that take a map that looks like the app state and event vector and return an updated version with the reduce happening in the framework. It's really close. The main advantage is that the event handlers are functionally pure and we can apply middleware functions to the handlers on a per-event basis, which we use for analytics, state coordination, input validation, chained event triggering, etc.
In the same controller namespace where we're registering event handlers, we also register topics. A topic is a registered reactive computation like a spreadsheet cell. I'm sure people have built the abstraction for Redux. We'd have `tasks` and `last-displayed-task` in the app state and register `displayed-tasks` (drop-while #(not= @last-displayed-task %) @tasks) and `new-tasks?` (not= @tasks @displayed-tasks) then have the task-list component pull out of `displayed-tasks` and the button show/hide with `new-tasks?`.
* For the "Show new changes" case, what you might do is maintain an object that does id->item storage of tasks, then have separate arrays of "task IDs being shown" and "task IDs that are new". The task list only cares about the "being shown" values, and in mapStateToProps, could show the "Show new changes" button if the "new tasks" size is > 0.
* You can also add additional logic in your mapStateToProps, or your component's componentWillReceiveProps functions to see how things might be changing.
* Per-component state in the Redux store is a topic of open exploration. I also have a list of Redux-related libraries over at https://github.com/markerikson/redux-ecosystem-links , and the "Component State" category lists at least a dozen libs that can dynamically put per-component data into Redux. That said, it's also entirely valid to keep data in your UI component's state as well - it's up to you.
Finally, if you're doing shallow-cloning and proper immutable updates to your state, that process shouldn't generally be a performance concern. Also, React Redux does a _lot_ of work to make sure that your wrapped component only updates when it absolutely has to.
There's certainly some good reasons to put as much of your UI/app state into Redux as possible, but there's also entirely valid reasons why you might not want to put some state in there.
* Both React and Redux have very small API surfaces, but do involve very different ways of thinking for someone coming from a jQuery or Backbone background
* While the "Javascript Fatigue" argument is a bit worn out by now, there _is_ validity in the point that there can be lots of moving pieces to set up
* There are some significant nuances with both libraries once you get past the "Hello World" stage. State shape, performance optimization, managing more complex use cases, etc.
Beyond that, there's a _lot_ of articles and tutorials out there, and the quality of the information varies considerably. I did a lot of bookmarking while I was learning these things last year, and have found myself answering many of the same questions over and over on Reddit and Reactiflux. I wanted to put together a consolidated reference of good information that I could point people to.
So no, you probably don't need to read "dozens" of articles to get started, but one person might find a certain 3 or 4 articles more useful than someone else (kind of along the lines of how "everyone uses 20% of MS Word's features... but everyone uses a different 20%").
I can't speak to the quality of this list, but I gather that, rather than a defacto list of how to go from 0 to expert on react and redux, the author intended to curate a list of tutorials that they found insightful so you don't have to go digging around Google.
Applications behave consistently because all state is stored in a single object, so it can't be desynchronized across components. Because all updates use a single function, it becomes easy to track and respond to any state changes by applying middlewares to that function. Things are more testable because all state is available for stubbing, and because the "reducer" is a testable, pure function typically composed of many other smaller, testable pure functions.
Things like time travel become possible because of the purity of the reducing function. Since it's pure, it can't modify the old state object (technically, it can, but it's against the rules). So in theory, we can undo any state change simply by loading the old state object from where it's being stored by some kind of history middleware.
The cons (you may/may not see them as such, but..) are
a. for a lot of people it is quite difficult to grok at first, b. it's extremely functional, c. it has quite a lot of boilerplate - it is extremely explicit, d. the app state is held in a single immutable object.
It also defines certain conventions around updating that data. In Backbone, anyone with a reference to a Model can call myModel.set("someField", someValue) at any time. In Redux, "write" logic is isolated to a user-defined set of "reducer functions", which only respond to specific types of messages. This makes it _very_ easy to determine when and why a particular bit of data changed. In addition, it enables scenarios such as storing the entire list of dispatched actions, and then playing back each action step-by-step to allow you to see how you got to a given state in your application (aka "time-travel debugging").
I'd say go with TypeScript if you're looking for a type system closer to C# or Java (including extensive OOP features), and go with Flow if you're looking for a type system closer to F# or Scala (including things like type inference and disjoint unions), although Flow supports ES6 classes, too. In my opinion, the Flow approach is a more natural fit for JavaScript.
That's not to say that either project can actually achieve the coherence and completeness of any language designed to be statically-typed from the start, but those are kind of the the type system ideals that each project seems to lean toward.
Also, Flow is fully integrated into the React ecosystem, since it's built by Facebook. TypeScript can work with React, too, but TypeScript also tries to give first-class support to many other frameworks.
TypeScript is undoubtedly the more mature of the two projects (Flow is much newer), but I'm very happy that both exist since they're taking pretty difference approaches to the "JS problem".
I also wouldn't say TypeScript strives to focus on OO features - we try to be a type system that works well for JavaScript programming as it exists, while paving the way for the future. We don't even use classes in the compiler!
Also like you mentioned, we try hard to work well with many other frameworks and I think that will show. Angular 2, Dojo, Ionic, RxJS, and others are even written in TypeScript and provide a pretty great experience.
If you mean give TypeScript a try, I have! In production. And it was very solid. I haven't yet tried the JSX tooling, since that's a somewhat recent development and predates my last serious use of TypeScript.
> I also wouldn't say TypeScript strives to focus on OO features
Every single tutorial and howto I've ever read for TypeScript, official or otherwise, has emphasized the OO capabilities of TypeScript. And for good reason, TypeScript adds multiple OO features, and features associated with OO languages like Java and C#. I've heard more than one C# dev say that it feels almost like programming in C#. So I don't think I'm off base here.
That said, it's great that you're looking to emphasize your support for more traditional/idiomatic JS as well, as well as your support for React. (and I admit I'm surprised you don't use any classes in the compiler. Every TypeScript project of significant size I've ever seen uses lots of OOP. But I'm sure you're aware of many that don't.)
I do wish that TypeScript had disjoint union/sum types like Flow does, but I just checked and it looks like you might be seriously considering it! That's great.
Actually, it looks like you're getting closer to the behavior I'd like with your recent string literal type PR. If you add some nice to use type guards, I could program in TypeScript in somewhat approximating the style I've come to love with Rust/Ocaml/Elm/Scala.
There's no way you could encode exhaustivity checks to that, is there? I'm pretty sure that would require true disjoint unions, right?
In any case, I'll have to take another look at TypeScript, I'm glad to see you're pushing things forward. I'll keep my fingers crossed that you'll end up adding disjoint unions as well.
TypeScript + JSPM really provides a nice productive and enjoyable dev experience vs regular ES5 - it's definitely my choice power combo going forward.
We could drop hot reload but it is occasionally nice
The TypeScript tools for Visual Studio automatically regenerates the .js file every time you save its TypeScript file so it works statically without needing any background process to monitor for changes. So my JSPM doesn't know about TypeScript, it's just loading the pre-generated .js files every time I hit refresh.
If you've configured React Routing and are saving/reloading Redux state in localStorage on change it's a pretty good dev experience as most of the time a refresh brings you back to where you left off.