If you're looking for something easier to use to help you manage state in your React apps look no further than Mobx. It's pretty incredible how stupid easy it is to use, it kind of feels like cheating.
I've tried to use Redux a couple of times but I just spent way too much time in plumbing code. Code I really don't care about. To be frank this code looks terrible (no fault of the author):
const handlers = {
[CREATE_NOTE]: (state, action) => { ... },
// ... a thousand more of this
}
Not to mention, I never not once felt happy working with Redux. I'm all about developer UX and working with tools that feel nice to use.
With Mobx you just declare a variable as Observable, then mark your components as Observers, and voila: You have crispy, no-plumbing reactivity.
In a way it kind of feels like Meteor where you save data on the database and it replicates everywhere it's being used.
I never understood why a lot of this was never handled with metaprogramming. I feel like it might have something to do with Redux using constants and imports as a type safety hack, but all the ceremony drives me nuts.
First we enumerate our actions as constants...
const ADD_TODO = 'ADD_TODO'
Then we need to create an "action creator" somewhere:
import { ADD_TODO } from '../actionTypes'
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
Then we need to import that action and dispatch it when we need it...
import addTodo from './actions'
dispatch(addTodo(text))
I'd highly recommend using a type system like Flow to enumerate the shape of possible actions the store should support. This brings numerous advantages:
1. You can use strings for action types, no more need to import constants.
2. No need for action creators for simple actions, you can just create the action object inline and Flow will validate its shape.
3. You can be sure that reducers are unpacking properties that actually exist from the actions.
In other words, your example could simply be:
// types.js
type Action =
| { type: 'ADD_TODO', text: string }
// TodoList.js
dispatch({ type: 'ADD_TODO', text })
...and Flow would confirm at 'compile time' that it matches the contract dispatch expects.
This approach has scaled up extremely well for me and no longer feels verbose.
I agree with that. When I first started with Redux and Flow, I was just following all the examples and made sure I used action creators for everything, even if there was no payload. Now I'm feeling more confident with Flux, and I recently realized that no, I don't need "action creators" for everything. That's silly. It's OK to just dispatch an object using your action constant directly.
And then I found myself writing action creators on purpose, not because I saw it in some tutorial, but because it actually does remove some duplication.
I had no idea why I was using a "payload" key, instead of just putting all the values in the top-level object. But this convention makes a lot of sense now.
That said, you are absolutely encouraged to abstract over that process as much as you want! For example, the https://github.com/acdlite/redux-actions library will generate both the action constants and the action creators for you, and there's many more similar utilities.
Personally, I find that when boilerplate gets out of control, you can do one of two things, probably in this order:
1. Write helpers.
2. Write middleware.
The first is zero magic, and allows you to opt-in to abstractions as needed. The latter is more powerful and can remove pretty much any boilerplate, but you have to be careful about introducing too much magic.
Redux isn't much different than any other code you might write. If you prematurely abstract, you could create a leaky abstraction, and you'll have to unroll the whole thing. If you don't abstract at all, and copy-pasta everything, you're also going to have a bad time.
Dan Abramov has said that the Redux docs were written in a deliberately verbose style to get across the ideas, and he didn't really expect people to strictly imitate that style. There's a wide variety of approaches and utilities you can use to abstract things as much as you'd like - that's entirely up to you.
- Put all the action types, action types, and reducers for a given portion of the application into one file. This is known as the "ducks" structure, per https://github.com/erikras/ducks-modular-redux .
- Write middleware to manage common logic for your application such as API calls
- Skip writing action creators and declaring action constants, and just have components do `this.props.dispatch({type : "SOME_ACTION"})`.
I don't recommend the last approach, but it's _totally_ up to you, especially because what you regard as "too much boilerplate" is going to be a personal opinion. One person's "too much boilerplate" is another person's "explicit and easy to trace through the system".
I developed a kind of meta programming pattern and supporting library, based on Redux, called Immuto, to get absolute and complete static typing (via TypeScript) and minimal boilerplate, also referentiality and modularity (cursors that accepted actions). It was fun, but ultimately pointless, as it was never as straightforward as using the automatic observable approach that I'd learned from Knockout.js. Then I heard about MobX (which is the same ideas from KO but better implemented and without any quirky UI templating thrown in) and so now I used that.
MobX is really cool, and I wouldn't try to convince anybody not to use it if it works for them. I happen to be pretty religious about immutable data, having been bitten by problems with shared mutable state so many times. I know MobX has actions which help a lot, but I still like the core simplicity of Redux, even if it means more typing.
My dream would be to have David Nolen (of ClojureScript) and Michel Weststrate (of MobX) do a panel where they discuss the essential differences and pros and cons of each approach. The philosophies seem at odds, but I think there's probably a core truth that neither side has fully reached.
Also, I think the core lacking thing of Redux is that it isn't really composable like React. I'm really curious to check out https://github.com/FormidableLabs/freactal since it aims to be a fractal (composable) alternative.
(And yes, props to Elm for having a built-in composable architecture.)
There is no immutable state, at best we have immutable data. Benefit of immutable data is you can inspect two different states when state transitions from state A to state B. You get time travel and all that with this basic concept.
MobX makes it very easy to do that inspection between states.
Don't look at mutable state as evil. Redux state is mutable too.
I've tried hard to like Redux as I have to work with it, but I can't.
At first I was perplexed by the boilerplate and the awkward way it seemed like I had to update 5 files just to toggle a view element -- but I figured I just didn't understand yet and one day when I did it would all make sense.
Well... after about a year of working with it, I'll admit I understand it and there is some sense to it, but there really is nothing elegant or likeable about it.
I too have never felt happy working with Redux.
I've got a side project I've been working on and was planning to use Redux since that's what I use at work, but I think I'll take this as an opportunity to try out something else.
While it wasn't really the original point, Redux picked up at a time where Angular 1 had a near monopoly. Redux got mindshare because it was the opposite. Do away with the magic, have a predictable flow, and virtually no framework. Just a design pattern where everything is explicit.
It got really popular because a lot of people want that. Typing is cheap. If a bit of boilerplate and a couple of files drastically affect your productivity, you're not solving a hard problem (and if you're not solving a hard problem, which is the common case, there are a lot of other tools better suited for it).
But because it got popular, everyone jumped on the wagon, including people who were not the target audience, or were not solving problems it was a good tool for. Now, people try to force Redux into being something else, and it really, REALLY sucks at that.
My suggestion is to try Mobx and write your code in TypeScript. It's a different concept when you first look at it but then you'll see it's actually mostly the same as Redux but with less boilerplate code.
You see something is flawed in Redux at the point you have to pass strings (uppercase constants defined somewhere) around, import them in every file, pass them as identifiers of what you should do with each data.
You don't actually have to do this if it bothers you. You can just use the strings inline, but the author (and many of those using Redux) finds it helps to reduce errors, by instantly pointing out typos.
There are also patterns to reduce the import issue. For example, https://github.com/erikras/ducks-modular-redux. I prefer defining my actions with my action creators in one big index, but the point is that there is absolutely a way to mitigate this concern if it bothers you :)
The point of keeping identifiers is to show you the intents of an action. If any identifiers seem silly to be added then maybe they don't deserve to be going through reducers in the first place.
if you use redux-actions your reducer can use an action reference directly- not its "type" string. developing this way I don't need to store references to these "constants" and they're only ever relevant when logging.
Here[1] is my take on a vastly simpler redux pattern, which hides both reducers and containers from application code, while at the same time requiring no middleware for async. It has worked wonderfully for our medium+ sized project.
Mobx is really nice. For a quick and easy database for an Electron app I added a Mobx observer that persists the state to a json file which is read back at startup. It was just a few lines of code and you get seemless persistence for free.
I've expanded on that idea for another Electron app I'm working on (http://www.serverwrangler.com) that encrypts the data before saving and has a database "server" in the main process so data is shared between multiple Electron windows of the same app.
I can't agree more. After using both there is no question that, for me, mobx is better. It is more intuitive and has much less boilerplate code. I've tried to understand why redux is chosen over mobx in some projects, and at this stage I feel it is mainly just momentum and visibility/marketing.
Since you mention Meteor. Why not just use Tracker? I feel that's such an underrated package. It's quite similar to mobx and it's been around for years. Combine it with minimongo and you've got a really flexible reactive state management.
"MobX usually reacts to exactly the things you expect it to. Which means that in 90% of your use cases mobx "just works". However, at some point you will encounter a case where it might not do what you expected. At that point it is invaluable to understand how MobX determines what to react to."
I'm going to be tossing and turning tonight trying not to dream about libraries that usually work 90% of the time.
This isn't about working only 90%. It means that it fits your current thinking to 90%. Only in 10% of your use cases do you have to dig deeper and actually understand how MobX works.
Unfortunately not, since those apps are all business internal.
On Android/react-native, the Kotlin parts runs on the JVM directly. I haven't released a KotlinJS-application to the wild yet, but I don't suppose the size is a problem after running it through webpack, uglify et. al.
You are right, the runtime is rather larger though. Do you have suggestions?
Mobx isn't ugly at all. Are you using decorators? You should.
Example:
import { observable } from "mobx";
export default class TodoStore {
@observable todos = [];
constructor(props) {}
}
// Elsewhere in a different file, now you just use it.
import TodoStore from './stores/todos_store.js';
import { observer } from 'mobx-react';
@observer
export default class Todos extends Component {
constructor(props) {
store = new TodoStore()
}
addTodo = (todo) => {
store.todos.push({ id: 1, text: "Get Milk" });
}
render() {
return (
// Just iterate over `store.todos`
)
}
}
As you can see you just use the variables and get stuff for free out of the box with no plumbing code except `@observable` and @observer`. What's not to love?
> How do two separate components access the one store, singletons?
You can use <Provider> and @inject to put a store onto the component tree and pull it off whenever you need it. It's just a quick wrapper around the React context API.
> If two components observe the same store but render different attributes of it are they both updated when the store is updated?
Yes, this is just how Mobx works. Observations are set up implicitly. You can observe any @observable value or @computed function just by referencing it within an @observer.
> Are you limited to modifying your store only in your component?
Nope, this works with just plain JavaScript. The main library doesn't offer any React-specific bindings (like Redux), so it can be used with anything.
Indeed, a good point to be aware of generally (though I would say we as a group go too far the other direction most times).
But the issue here with that is that I can solve the business needs in React+Redux trivially without running into the architectural problems I mentioned in MobX.
So why on earth would I chose the inferior option?
I swear, there are some users on HN (like yourself) that think FUD is some kind of magic pixie dust to invalidate someones statement. I thought we grew out of that in the early 2000s.
If anyone is interested in learning this content through an in-depth video tutorial, I highly recommend Dan Abramov's two-hour "Getting Started with Redux" [1] and the excellent follow-up "Building React Applications with Idiomatic Redux" [2]. This is a great article, but learning Redux more thoroughly directly from the creator himself may be of interest to some!
I came here to point out the Redux course by Dan Abramov on Egghead.io as well. I believe it's free. It's amazing how easy Dan makes it seem. It was a light bulb moment for me and finally made me understand the importance of immutability behind the React philosophy.
React's default behavior is that when a component re-renders, _everything_ underneath it in the component tree re-renders as well. If you want a component (and its descendants) to skip re-rendering, you can implement the `shouldComponentUpdate` method. You can put any logic you want into `sCU`, but the most common implementation is to compare the contents of `this.props` and `nextProps` to see if anything actually meaningfully changed.
You _can_ do a "deep equality" comparison that recurses through every nested field in both `this.props` and `nextProps`, but that's relatively expensive. The alternative is "shallow equality", which uses pointer/reference equality checks for each field in both objects. However, in order for that to be useful, you need to manage your data in an immutable fashion so that each update results in a new object/array reference, rather than directly modifying the existing objects.
So, you don't _have_ to manage data immutably in React, but doing so enables performance optimizations, and also goes along with React's functional programming influences.
Gotcha - so you see it mostly as just a perf optimization based around SCU?
Funny timing. I was actually implementing SCU using deep obj equality for the first time earlier today. I did understand the desire for immutability, but it didn't seem to be a game changer.
Perf optimization is a big benefit, yes, but it also fits with functional programming principles in general.
React's `setState()` definitely doesn't care if you mutate or not - you can `.push()` right into an existing array in state, and re-set it into state to queue the re-render.
On the Redux side of things, immutability is important for several reasons. First, pure reducer functions are more easily testable. Second, they enable time-travel debugging - without immutability, jumping back and forth in state would cause the state contents to behave unpredictably, breaking time-travel. Third, the React-Redux `connect` function relies on immutability checks against the root of the state tree to see if it _thinks_ anything has changed, and against the return values of your `mapState` functions as well. If you mutate Redux state, your connected components usually won't re-render properly, because they think nothing has changed.
You're comparing reference to infer whether underlying data changed? Sounds really really fragile... Does the JavaScript language guarantee this or are you depending on the specific engine implementation? For instance will this still hold if the OS preempts the browser out and restores it later?
That's an absolutely standard practice in Javascript, and especially in the React world.
The assumption is that if two objects are different references, then their contents are also different. It's possible that you could have two different objects whose fields point to the exact same contents, but given a typical application setup that's unlikely. So, a simple `a === b` (or if you're looking at all the contents, `first.a === second.a && first.b === second.b && .....`) is just some quick pointer comparisons in the JS engine. So, at the JS level you don't care what the pointer address actually _is_, just whether the two variables point to different things in memory.
Agreed, Dan's videos are great! Sometimes I've found people still thinking there's some magic going on inside Redux, so I just wanted to do my best to remove that.
Last summer I said to myself, "Okay I need to know what all the fuss is about." So I sat down and read the Redux source. I thought, "This is it?" It does almost nothing but issue loquacious console warnings when you're doing something you're not supposed to.
The complexity is mostly from people approaching it from a confusing direction. Some of the naming is confusing ("action", but actually it's an event or message, is the worst one). Somehow everyone comes away from the tutorials and docs thinking that the typical code structure used in them has to be how you do it (see many of the complaints on this very page) as if it's much more a framework than a library.
I had a similar experience with it coming in to a recently-started React Native project at work, having not seen React, React Native, or Redux before. At first I was fairly confused (see: awful terminology, painful example code which everyone seems to take as gospel and which had, in fact, invaded our codebase).
Then I started to get an inkling that I was being tricked. I looked closer and... it's two event dispatchers. One of which it's mostly up to you to implement (the reducer). Plus a really short list of suggestions for how to write the code (mainly: don't screw with state in certain places/ways). That's it.
It's paper thin and dead simple, but somehow most people come away from the tutorials and docs hopelessly confused. I think there's something deeply and perhaps irredeemably wrong with the docs/tutorials and with the way Redux's proselytizers communicate. I can't figure out how else they could manage to confuse so many people about such a simple thing.
You've said that several times, and I'm genuinely asking: how should the docs handle things differently? If you have ideas and suggestions, _please_ file an issue or a PR and help us improve them!
The docs are fine. Redux is just a victim of its popularity. A lot of people jumping on it are people who are used to things like Rails, where there's one way to do things, every little bit of boilerplate is abstracted away (and if you don't want to do things this way, you're screwed) and you don't ask questions why.
Redux is the polar opposite. No amount of documentation will change that. The faster we accept that not every tool is the right one for everyone, the faster we can make better tools that are great and some stuff instead of being mediocre at everything.
I know it's not for everyone, and I know discussions won't convince everyone. I'd just like people who are complaining about the docs to offer some constructive help :)
TFW you see a thread about Redux, and you just _know_ that the comments are going to consist of nitpick complaints.
Contrarian opinion (apparently): Redux is a lifesaver when it comes to complex applications. There's a little more ceremony, but a lot more organization, a lot fewer bugs.
Exactly. I ported something I wrote in angular to react+redux. The angular version was super short and worked most of the time, but I had a bunch of weird state/race conditions/display issues I could never resolve.
Porting it to redux meant:
Wire up the reducer with enough initial state containing dummy data so render() works correctly.
Add buttons that dispatch actions. Use the debug tools to verify that the proper action gets logged. If it's an action like `LOAD_EXAMPLE` verify that `example` contains the expected name of the example.
Once the action is being logged properly handle it in the reducer. Use the debug tools to verify that the state is being changed as expected.
At this point the feature should be working. old state -> action dispatched -> reducer -> new state.
Having things separated like this means that you only ever have 3 kinds of issues:
1) The wrong action is being raised. Solution: Fix the event handlers or the action generator that calls dispatch. If the action is wrong no need to look elsewhere.
2) The reducer is returning the wrong new state. Solution: Fix the reducer. If the action was right and the new state is wrong, the reducer is the problem.
3) The app is rendering wrong. Solution: Fix the component. If the new state was correct but things look wrong, the only possible place the problem can be is the component.
Is this verbose? YES!
Is this complicated? NO! It's a lot of very simple javascript functions that do one thing at a time.
However I develop enterprise CRM app. In db there are 200k client records, 500k sales calls records. It is implemented as a standard Ruby on Rails / Postgresql web app. It works quite well. It is also pretty straightforward to implement a such app in a Java/PHP MVC framework.
Let's say I would like to implement UI using React/Redux. How should I start? For example the app has calendar month view, for each day there are 20 sales calls. So the month view has 400 sales calls and clients data displayed (date, time, client name, target group).
Do I have to put 400 sales calls and 400 clients data to a Redux store to display the calendar month view? What about client data search results and pagination? In just few clicks a user can display hundreds of clients records (thousands in case of results map view). Do they belong to a Redux store? If a user modifies one sales call record, how it is persisted in central DB? What about edge cases where some uniqueness conditions have to be checked on central DB level?
Rails covers all things needed to implement my medium CRM app. When I read Redux TO DO tutorials I have a filling that they cover just 10% of what is needed to implement a full CRM app. Could you please direct me to Redux examples / tutorials how to implement a full enterprise database app (SugarCRM scale).
PS. to down voters, please write a few words what is wrong with my questions so I can learn what is appropriate to post on HN
I upvoted you, because I think this is a total legitimate question and I don't get the downvotes either. This was exactly the question I had, when I read about Redux at first. After all, the Redux docs say that "don't worry about performance, unless you have tens of thousands of objects".
So, the answer I can give you as someone, who starts to get Redux, but I'm nowhere near being an advanced user:
In your Rails app, you wouldn't render all 500k sales records on the same page as well. You'd probably have some sort of pagination. With Redux, it's the same. You don't have 500K objects in store, but only the 30 sales calls you're currently displaying. Redux contains the state of the current view and if you want to load more data, you'd have some async methods to fetch data from the DB or an API and refresh the Redux store.
But still: Many tutorials are way too simple and gloss over the details. They make it sound as if Redux is the architecture and the store holds all data for the entire app.
What I haven't figured out: Say, you're using Redux on the server and need to update all 500,000 sales calls. With Redux, you'd have to write a reducer that modifies the state tree. But if 500,000 sales calls don't fit into memory, how do you do it?
it doesn't sound like redux is the right tool for the job. You're looking for a stream/file.
You could still have a redux store, but it's role would be to manage the stream(process updates, keep track of errors, kill the stream if there are too many errors) rather than store the data for the job.
Neither React nor Redux really prescribe an architecture so building an app with these libraries requires some extra thought over just using a framework. An approach I often see is to use Redux as a single state container in a monolithic flux architecture (which seems to be referred to as "Redux") but this has advantages and disadvantages, and is certainly not the only way to use these libraries.
If you're going to go down the flux path, I would suggest you map out the minimal state which can completely represent your user interface (store structure), then list all the state mutations (actions) which you expect to affect this state. That might help you build up clear picture for how to develop your CRM app.
It's good to keep in mind that at the end of the day React and Redux are just tools, and it is up to you how to use them.
My initial answer to that is that none of those questions are specific to React or Redux, but rather are common to _any_ Single Page Application, whether it be written in React+Redux, Angular 2, Angular 1, Ember, Backbone, or good ol' VanillaJS/jQuery.
More specifically: yes, you would typically make AJAX calls on app startup to load some subset of records from the server, and continue to make more AJAX calls to request more records as needed (like when the user hits the "Next Page" button). Records requested from the server would indeed be cached client-side in the Redux store. When the user modifies an entry and hits "Save", you'd make another AJAX call to persist the updated values to the backend. Again, none of that is actually Redux-specific - it's just general workflow for an SPA.
Some resources that may help. As mentioned elsewhere in the thread, I have a list of React/Redux tutorials and articles [0]. The "Redux Tutorials#Project-Based Tutorials" section [1] specifically lists tutorials that try to build something (preferably bigger than a TodoMVC app), rather than just explain the basics. In particular, the series "Building a Simple CRUD App with React and Redux" [2] is an excellent 8-part walkthrough that covers many key real-world concepts. I'll also put in a plug for my own "Practical Redux" tutorial series [3], which demonstrates some specific useful Redux techniques. Finally, you might want to glance at the "Redux Architecture and Best Practices" page [4] in my list for more articles on real-world approaches and concepts.
I like this article. It's probably a good idea to build your own simple todo app using Redux from scratch first, and then follow this guide. It would make a lot more sense.
Using this as a place to put some thoughts on Redux after having picked it up over the past few weeks.
I have been spending the least few weeks re-writing an "offline-first" mobx React app into Redux, after it started spinning out of control and becoming unmanageable. Mobx provided a lot less guidance on how to structure a larger app (read: more than a few pages with non-trivial remote interactions)
Like React itself, it took me a few weeks to grok the philosophy and architecture, and internalize the key components so that I wasn't getting lost every few lines of code.
I had evaluated Elm earlier in the year but passed on it, as there were some interop issues, and the component ecosystem wasn't as mature as react.
Redux has had the effect of organizing my code and helping me reason about the structure, as well as providing time travel for free.
Typescript to be very helpful when building with Redux, specifically when I did something wrong, and had to refactor.
I've also been pleasantly surprised at the middleware ecosystem, and how useful and easy to configure it has been.
First I pissed off on Elm, and have been observed many the leader's reasons behind things people do not like. However, it is hard to make arguments against reasons from his point of view (e.g. https://github.com/elm-lang/projects/blob/master/roadmap.md)
Now, it really makes sense to me that he made it hard on JS interop and discourage js-wrapped packages. We should move forward, even WebAssembly team, as I imply, want to ditch javascript completely (But people don't want to say it out for unhealthy discussion) Here is a talk about what/why/some how/ on WebAssembly https://www.youtube.com/watch?v=OH9NYzH3-74
We don't need "component" things in Elm, though if you mean "module", I'm sorry. I really don't understand why people still build things on top javascript that is fundamentally and practically wrong (No need to elaborate _this_!)
You can replace redux with any FRP library. Your state is a signal/stream/whatever that folds over an initial state with a signal/stream/whatever of actions/messages. Your top level view component should listen and render based on that. Example: https://github.com/twfarland/sprezzatura-acto-mario
Yeah, I'm pretty amazed at the amount of attention that a simple "fold"[1] gets in JS-land.
Yeah, OK, Redux (etc.) is also a little bit of a pattern for sort-of-algebraic data types, but really... I prefer using a language that actually supports algebraic data types natively like Scala.js, Reason, Bucklescript, js_of_ocaml or GHCJS.
I appreciate that these may not be an option for everyone, but at least one of them should be an option for the vast majority of current frontend developers.
[1] Well, technically I guess it would be a foldM?
I have to deal with Redux at work and I absolutely hate how much code I have to write to flip a binary in my React component!
I used MobX on the side projects and I absolutely love it! I might be biased but I think MobX is so much better for any size project. Redux is just too good at marketing and their "Hello world" looks very very interesting and reasonable but it doesn't scale. When you have multiple people working on the same codebase it becomes a hot mess!
If you're starting a project, give MobX a shot and see how it goes.
Oh man, everyone's talking about MobX in here, and I've never really looked at it. This looks pretty awesome. I don't particularly enjoy using Redux either, so I think I might try this out on my next project.
What do you use instead of redux-saga or redux-observable? E.g. for async stuff like ajax calls, or listening for events and emitting new events?
Concrete example: You want to listen to a variety of events in your app, and send analytics. Some of your analytics events require looking up parts of the state and doing some processing. This is really easy to do in redux-saga, but how would you do this with MobX? Or would you use something else for this?
One advantage of Redux that people tend to miss is the serializable state object which is incredibly helpful for local logging and remote debugging. It's the reason we built LogRocket (though now we have a bunch of other features for general web apps).
Looks like a standard ES6+ object literal to me. ES6 allows you to shorthand `{someVariable : someVariable}` as just `{someVariable}` (ie, create a key whose name is the variable name and whose value is the variable value). There's some good overviews of ES6's new syntax and features at https://ponyfoo.com/articles/es6 and http://es6-features.org/ .
The syntax isn't meant for you to have to create a temporary variable in order to use it; that would be pretty pointless. It's meant for cases when you already have a variable with the same name as the key you want to set.
Right. But in almost all cases I'd prefer to do away with it entirely, and not encourage extra variables for the sake of usage. It makes code more ambiguous (for anybody not coming from javascript and being used to it)
How does it encourage to use extra variables? If you have a variable with the name use it, otherwise do whatever you usually do like calling a function. It doesn't encourage doing something like
const id = getId();
let obj = {id, otherProp: 'something'};
vs
let obj = {id: getId(), otherProp: 'something'};
?
It's a minor piece of magic that I don't see a particular reason for that requires ever so slightly more cognitive overhead. The ambiguity is in context of switching between languages, really.
This is a great article! As I commented on the post itself when it was published, I keep a big list of links to high-quality tutorials and articles on React, Redux, and related topics, at [0]. That includes a section of "Redux implementation walkthroughs" at [1]. This is probably the best article of that type that I've seen. It not only covers the core of Redux, but also builds miniature versions of Redux middleware and the React-Redux `connect` function. I already added it to my list, and definitely recommend it.
Readers may also be interested in my Redux addons catalog at [2], which includes links to hundreds of Redux middleware, utilities, and other useful libraries. That includes multiple ways to batch dispatching of actions.
I am probably going to get downvoted to hell for this negative comment, but please stop doing this. I am really tired of seeing your "big list of links" everywhere I go[0][1]. If I click on anything even mildly related to React, Redux etc., on Reddit, HN etc. I always find the same thing.
Personally, I don't mind it. The resource seems genuinely relevant and useful, and the few lines it takes up as an HN comment don't significantly distract. While you may have seen it over and over again, that doesn't mean everyone in the community (and anyone new the community) has seen it. I'd rather have to skip over info I've seen before than make it less accessible.
If the content is not appropriate to make it a relevant addition to the discussion, then that should be the point of contention, not merely that you've seen it before.
I upvoted you. This feels a lot like marketing spam. I think we instinctively upvote comments like this, but we really don't need it on every react/redux post here. Is the list popular because it's useful or because the author tirelessly promotes it? No way to tell.
Besides the above, both react and redux have excellent official documentation, and tutorials get stale.
I agree that both the React and Redux docs are good, although I'm biased - I wrote the Redux FAQ and "Structuring Reducers" sections for the Redux docs.
That said, the official tutorials and reference sections can only cover so much info, and other articles often go into more detail. For example, the React docs discuss the idea of "controlled inputs", but Gosha Arinich's series of articles on React and forms [0] go into much more detail on the concept and how to apply it. The React docs mention immutability somewhat in the "Optimizing Performance" section, but there's other articles that discuss the why and how in greater detail [1].
Similarly, the Redux docs try to teach the basic concepts and important principles, but articles like "Redux Step by Step: A Simple and Robust Workflow for Real Life Apps" [3] and "Advanced Redux Entity Normalization" [4] go into a lot more detail on some useful real-world concerns.
In the last couple big React-related threads on HN, some people complained that there were no all-encompassing guides for React, the way there are for things like Django or Rails. A lot of that is because Django/Rails are much more convention-driven, so there really is more of an "official" way to do things. With React, people are free to pick and choose the pieces they want, and that means that a single guide is somewhat impractical. (The React team also does not want to try to push or enforce specific tools as "blessed", partly because Facebook has its own ways of using React that are different than the community, and also because they believe in letting the community build things that solve their own use cases.) As a result, in a lot of ways my list is about as close to a "guide" as you're probably going to find for React best practices and resources.
Yeah, I paste the link in a lot of places, because people keep asking the same questions, and the vast majority of people who see my list find it helpful :)
It's really a case of XKCD's "Today's 10,000" ( https://xkcd.com/1053/ ). There's always some people who find out about something for the first time, and I'm trying to help those people.
FWIW, I do try to include those links as part of a larger comment relevant to the article or discussion at hand.
That was a wonderful XKCD reference, and an enlightened response. I had seen your Redux list before too, but I appreciated seeing it again as a reminder, it's relevant to the discussion and a great resource, especially for those starting to learn about the topic.
A big list is a negative thing, not a feature. When you have twenty links to introductions to React, they all seem equal and thus the list is no more useful than a google search. A small, curated list, that would be useful.
I do have a shortened, "best-of / getting started" subset on the front page. As for the similarity between links... yeah, there is some duplication, but different articles take different approaches to describing things, and might help different people. Also, having them all in one place makes it easier for people to browse through them, rather than having to fully sort through Google results themselves.
I'd also welcome any help maintaining the list (organizing, updating, pruning, etc), because thus far it's been only me :)
I like this resource specifically because it's such a large list. If I'm exploring a new topic (e.g. styling react components), I want to have a lot of articles to look through. Google doesn't cut it at all for me in situations like that.
"Redux is a simple library" woah woah stop right there. How is this:
const handlers = {
[CREATE_NOTE]: (state, action) => { ... },
// ... a thousand more of this
}
simple? This looks horrible. Every time you want to work on code that modifies data, you have to switch to the one file where you keep all the data-modifying functions? Seriously?!
Freezer https://github.com/arqex/freezer is a much, much better experience. You just shove immutable objects down the component tree, and they just come with methods that modify "them" (by actually changing the data tree). It has an event system as well for when you actually want to centralize actions. Works great with Polymer, by the way!
Sounds like you're confusing 'simple' with 'easy'. Rich Hickey does a good job of contrasting the two in Simple Made Easy[0].
The essential part of Redux is only 44 lines of simple code [1]. You can understand everything that it is doing. That is simple. It doesn't mean that it's going to be a great experience to work with (you might want to add some abstraction on top to make it also 'easy'), but it is definitely simple.
You're complaining about a couple different things. That particular reducer example is a bit terse, and could be made more readable. That said, yes, Redux (as a Flux Architecture derivative) does ask you to separate all your "write logic" from the rest of the application. This is explicitly part of the design.
I'm also working on a blog post that will discuss the actual technical limitations Redux requires of you, vs how you are _intended_ to use Redux, vs how it's _possible_ to use Redux. The goal is to clarify where the various common aspects of Redux usage come from and why. I'm hoping to finish the post over the weekend and publish it early next week. If anyone's interested, keep an eye on my blog at http://blog.isquaredsoftware.com .
> you have to switch to the one file where you keep all the data-modifying functions? Seriously?!
Of course not - and I strongly urge you to think through things like this more deeply before writing them off.
Redux is a really good and well-thought-out library. I'm sure you could think of multiple solutions to the problem you just proposed, including splitting that file into multiple files. It would be a shame if you never took the time to understand the library because you got caught up on simple trivialities like this.
Of course, and that's the huge win of Redux. Forcing you to separate out state updates wraps them in a layer of indirection and allows you to operate on them at a higher level than otherwise possible. This makes ordinarily difficult operations simple and elegant. You can use the higher level of abstraction to get undo for free, or replay them to find bugs, time travel, or send them across a server to get a multi user app. What you're saying is "more complicated than it needs to be" is in fact the revelatory idea of Redux.
I reiterate myself: you should try to understand Redux more deeply before writing it off. You are doing it a disservice.
Why do you need this separation to get these things?
In Freezer, you can do transactions directly in your view event handlers, and one transaction is one update, and .on('update', (currentState, prevState) => {…}) you can save the prevState into your undo log. And when you want to separate a data manipulation action, you can use custom events to do so — but you aren't forced to! It keeps simple operations simple.
Are you really just opposed to doing things in different files?
I'm going to divert the conversation away from Redux entirely if that's the case. You should invest in an editor with good "go to definition" support. I had a similar problem, but as soon as I did this, the pain threshold for switching files dropped to nearly 0.
(If that's not the case, do keep on mind that a file separation is totally unnecessary. You could write your state manipulators inline if you wanted. I feel it is a bit organizationally messy, but hey, whatever you like.)
Well I hope you realize that coming onto a topic about Redux and claiming Freezer is better without really understanding Redux internals may not be the best way to proselytize. :)
The size and complexity of your app is an important factor here. If only one view in your app needs to touch the state in a certain way — say, fetching some data from an API and updating a view — then it might make sense to manage that state in your view. But if multiple components in various parts of your app are making similar kinds of calls, it makes sense to manage it centrally, with a file or set of files that can handle common actions.
I think you could swing that, you'd just have to dispatch a more complicated "action" (event/message) from the handler and write a master reducer that expects incoming actions (events) to contain their own state-managing (possibly, though not necessarily, static) method under some common interface, and called that method (returning its result). Basically each action/event would contain its own reducer, which the master reducer would call. Once done (pretty sure it'd be trivial?) you'd never have to look at your master reducer again.
It'd all live wherever you like, and be passed on to the master reducer via dispatch. Handler/"action"/reducer could live together, as you please.
It's possibly I'm wrong, as I've never done this, but I don't see why this or something fairly similar couldn't work, with little set-up.
Redux gives you a combineReducers() function for splitting your reducers into separate files. The way I structure it is by which section of the state object they modify, so that I have a reducers/stateA.js, reducers/stateB.js, which correspond to a state object that looks like { stateA: { ... }, stateB: { ... } }.
I think it's definitely worth considering other solutions, as Dan himself has mentioned that Redux isn't for everyone. Redux forces you to apply some constraints and make some tradeoffs. I personally like those constraints and tradeoffs, but I can understand it's not for everyone!
"simple" and "verbose" are not the same thing. I agree that Redux is overly verbose, but what it's doing is actually very simple. That said, I avoid it because I dislike having to write actions for every single operation I want to do on my data.
To be fair, you can (and should—I really don't get the appeal of the typically-presented way of using Redux) do things very differently if you like. It's not hard to group actionCreators (actions), actions (events/messages—Redux terminology is pointlessly n00b-hostile), and reducers, and even stick them somewhere closer to (in if you really want to) your views.
That, and that the tutorials/beginner-docs don't all start, "look, it's pretty much just two really really simple event dispatchers stuck together, so don't panic" followed by an implementation-focused walkthrough like this.
Redux is way too simple to justify the amount of writing there is trying to teach people to use it[0]. It's two event/message dispatchers. Events/messages move through them thusly. Here's the tiny interface by which you interact with them. Don't do this or this unless you want bugs to happen, and here's why. Done.
I couldn't agree more strongly. Something weird happens to FP proponents such that once they get very good at it, they lose all ability to explain or empathize with beginners. :)
One of the most frustrating thing about FP land is that I never feel confident I actually understand anything. Every time I think I might the explanation I arrive at is so damn simple that I can't convince myself it's truly correct because there's this mountain of confusing explanations in my wake, and why would anyone have tried to explain it that way if it were actually this simple?
(Seriously, I mean it - most of my work as a Redux maintainer has involved improving the docs, and I genuinely am interested in having people help improve them.)
For what it's worth, most of that comes directly from the Flux heritage. For example, the Flux docs at https://facebook.github.io/react/blog/2014/07/30/flux-action... explicitly describe the terms "actions" and "action creators" . There was a lot of discussion and bikeshedding in the early Redux issues over whether to use terms like "events", "commands", or even "facts" instead, but Dan and Andrew opted to keep "actions" for consistency with Flux. (Really, a very large percentage of questions about "Why does Redux do $THING?" can be answered with "Because the Flux Architecture, or other existing Flux libs, did things that way first".)
"Reducers" come from the similarity with the callbacks passed to `Array.reduce()`, "thunk" is an existing CS/programming term, and "saga" was also adopted from the backend world. So sure, a lot of these terms are new to most people (especially front-end developers), but they were generally based on existing terminology and not just picked out randomly.
It's not that I don't understand there were reasons for choosing the names. I just think they were confusing reasons. :)
It reminds me of Haskell, where monad is such a terrible name. Same with functor, applicative functor, etc. Yes, all these names aptly and mathematically describe what they do, but the most precise name will not help beginners understand.
For instance, if reducers were called "state updaters", I think people would be less confused. Same if "map state to props" was called "get props from state".
Sometimes you gotta give up on giving the most precise name and instead give a name that is the most clear for the greatest number of people.
FWIW, I agree with you--I feel like there's a distinct "pull the ladder up behind you" notion in the land of bleeding-edge software (not just FP, but I'm lookin' that way), where a vocal and influential chunk of the community has decided (and enough others have followed along) that a certain kind of exclusive specificity and conscious choice of high-level vocabulary matters more than the other people who might benefit from the stuff. And then inertia means things don't get better.
Many programmers are bad at naming things. Many are bad at doc. None of this stuff is actually hard, it's just made hard and made unfriendly in unfortunate ways.
Not really. You have a state model, once you change it a new immutable slice is created, maintaining the nodes that didn't change. That makes it possible to check for changes with reference equality (old === new), which is fast. Components simply pick a portion of state they're interested in and render once it changes.
That makes your app transparent, meaning what you see is just a reflection of state. State changes, app reacts, state changes back, app is the same as it was. You can slide through your apps history in dev-tools and see it construct/deconstruct itself, it's also very easy to inspect and see what action led to which result: https://camo.githubusercontent.com/a0d66cf145fe35cbe5fb34149...
Redux is a pattern basically, it's pure javascript, no magic, and little behind the scenes stuff.
https://stackshare.io/mobx
I've tried to use Redux a couple of times but I just spent way too much time in plumbing code. Code I really don't care about. To be frank this code looks terrible (no fault of the author):
Not to mention, I never not once felt happy working with Redux. I'm all about developer UX and working with tools that feel nice to use.With Mobx you just declare a variable as Observable, then mark your components as Observers, and voila: You have crispy, no-plumbing reactivity.
In a way it kind of feels like Meteor where you save data on the database and it replicates everywhere it's being used.