I'm just about to start a large redesign with redux for work, and I'm just getting into Typescript vs Flow. Do you have any comments about how they compare?
Haven't use Flow in anger but TypeScript has a lot more momentum, tooling, community and dev resources behind it which are the main reasons why I've adopted it.
TypeScript + JSPM really provides a nice productive and enjoyable dev experience vs regular ES5 - it's definitely my choice power combo going forward.
TypeScript is fairly mature and conservative, whereas Flow has some reasonably innovative and bold (for JavaScript!) features.
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".
Hi, dev on TypeScript here. I would not just say that TypeScript "can work" with React, but that it is really very good, especially in terms of JSX tooling. Give it a try some time!
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.
If you have an existing codebase already using Babel and Webpack or Browserify, then using Flow only requires tweaking Babel's config a little (or not at all if you're already using the React preset). You use Flow like a linter tool. It doesn't try to take over your build process; You don't have to leave Babel and Webpack/Browserify behind. Flow is also great for allowing you to gradually add typing to an application.
Did you manage to get hot reload working with TypeScript (without going through Babel in the middle)? Currently using webpack + typescript but still have Babel in the middle for the occasional hot reload.
We could drop hot reload but it is occasionally nice
No I've opted to go with the least moving parts and am not using hot reloading or any runtime transpiling/transformations/etc.
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.
Look at this recent pull request by Dan https://github.com/reactjs/redux/pull/1455
It removes the need of the hmr plugin and babel completely, since it uses webpack hot reload directly
I've seen that before but I couldn't get the hot reload to work for the react components. You also need to `module.hot.accept` every file one by one I think?
Was going to ask for a TypeScript suggestion, thanks! I wonder how far off the VS Studio setup is from Visual Studio Code as I've been using the latter lately.
Maybe I'm missing something, but isn't the appeal of the React/Redux stack that it is simple?
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)
* 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%").
No matter how simple a piece of technology is at face value, people often use its simplicity to solve complex problems. Sure, building a TODO list with react and redux is easy enough, but once you start building a large or complex application you need to establish patterns and design decisions in order to scale the codebase well.
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.
Exactly. It's specifically intended to be tutorials and information that I have evaluated and determined to be well-written and informative, so that it's a one-stop set of resources for someone wanting to learn.
So what problem does Redux solve? From its doc: "It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test." Sorry, I am not sold. Can anyone summarize what problem it solves in a short paragraph?
It's state storage. If you've got any familiarity with Backbone, all of your Models and Collections define the current set of data for your application. You may also have a lot of UI-related state, like which tab is selected, which pane is open, etc. Redux lets you put all that information into one place (although how much or how little of your state goes in there is up to you).
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").
Redux tries to enforce a convention that all application state is stored in a single object (the "store") and modified using a single pure function (the "reducer"). These conventions make it easier to reason about the application's current state.
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.
It's a method of dealing with the state that is extremely simple. The state is a single immutable object. The bits of your app emit actions, which are just plain JS objects. The state is updated by running a reduce function [on the bit of it you want to update] it in response to the action. That's basically it. The 'easy to test bit' isn't an exaggeration; there is no magic at all, and every component part is extremely basic. Behavior becomes very predictable. The source of truth for the app is moved almost entirely to this state object, all other state/side effects are discouraged wherever possible.
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.
The surface area of react and redux is small and simple, but that doesn't mean that building complex applications with it is easy. Essentially, redux is just a big reduce on an immutable object. The just here is what makes redux great and open many possibilities with the time travel, etc.
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? :)
I'm already using immutable objects, this is a separate issue. The question is about how to keep the UIState (Say inside a component) in sync with the AppState considering they both evolve differently?
The official Redux answer way is to use app state for everything. See libraries like https://github.com/erikras/redux-form which move all the field state into your app state. Personally I break that rule when I know I can. The only other state I can think of is animation state - but using css transition animations has just worked out for me so far.
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.
* 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.
> 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.
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?`.
32 comments
[ 3.0 ms ] story [ 80.6 ms ] threadhttps://github.com/ServiceStackApps/typescript-redux
TypeScript + JSPM really provides a nice productive and enjoyable dev experience vs regular ES5 - it's definitely my choice power combo going forward.
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.
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.
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)
* 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.
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").
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.
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? :)
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.
* 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.
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?`.