8 ms·
There seems to be a big blind spot in these Real World React+Redux tutorials when it comes to forms. For example, say I have a page with reviews on it. So the
by fpgaminer 10y ago
There seems to be a big blind spot in these Real World React+Redux tutorials when it comes to forms.
For example, say I have a page with reviews on it. So there's a Component that handles editing a review. Where does the state for all the form inputs go? Does it go in the Redux store? If it does, then every time the user types a letter you get an event, which goes walking backward through the component tree until it hits the review editor Controller, which generates an action, which dispatches to the store, which gets reduced causing a state change, which then percolates back up through the Controller/Component tree to finally add that letter to the input. That walking back and forth is bad enough on its own, let alone generating an entirely new state (because the state is immutable) for every single letter the user types. It's inefficient, and it adds noise into the action log.
The alternatives seem to be storing the state in the component in which the typing is happening, or in the parent Controller, and then only generating update actions against the store when some "finished typing" event occurs (i.e. onBlur or timeout). Of course this seems to go against the idealistic implementation of Redux where all the state is stored in that one state object and it's immutable.
My point being, I haven't stumble across a "real world" tutorial that goes over this stuff. I wouldn't quibble about that normally, as I'm happy to play around and find the solution on my own, but this feels like such a common and important task (what website doesn't have forms of some kind?) and the performance and maintenance implications of how this is implemented seem large. So it would be nice if there was a "We built this huge web app using React and Redux, this is how we ended up doing forms and it works well for us" article.
- JasonSage 10y agoOne small nitpick > let alone generating an entirely new state (because the state is immutable) Assuming you're talking about the redux state, this is only if the state changes. Dispatching an action to change the state of your form should cause the form's entire state tree to change at most, and possibly as few as one or zero objects. All those other redux reducers that just return the previous state are not going to have any performance impact. In effect, your state is immutable but you're only getting "new" state references for a small portion of the state atom, very cheaply.
- idbehold 10y agoIt all depends on what's going on in the render method and/or shouldComponentUpdate.
- Vekz 10y agoI'd suggest looking at https://github.com/erikras/redux-form https://github.com/erikras/redux-form
- tomtau 10y ago100% agreed, the current standard seems to be redux-form but I've never heard of any serious production build using it.
- Lazare 10y agoEveryone basically just uses Redux Form (http://redux-form.com/5.2.5/ http://redux-form.com/5.2.5/) as near as I can tell; it really works well. It basically works as per your first guess: Everything goes in the store. And no, it doesn't really have any performance or efficiency issues. Try it out and see. :)
- iyn 10y agoFor improved performance (especially on big/complex forms) I suggest looking/using v6 (technically still in alpha, but stable).
- Koromix 10y agoThe overhead for a simple textarea seems significant. On Firefox there are stalls (up to 500 ms) if I type "fast". I've tested the form on http://redux-form.com/5.2.5/#/examples/simple?_k=8ukhm8 http://redux-form.com/5.2.5/#/examples/simple?_k=8ukhm8 (specifically the textarea). Here is the CPU time graph during my tests: http://imgur.com/we9uGQ7 http://imgur.com/we9uGQ7 EDIT: OK apparently it's not accurate, see comment below.
- marshalltony 10y agoHe has redux dev tools enabled which might be causing issues with performance. We use redux-form for a medium project and have had zero performance issues. If you have huge forms you may run into performance issues but those are also gone in the new version.
- fpgaminer 10y agoConfirmed; just tested on my machine (Firefox, i7-3632QM @ 2.2GHz) by mashing on the keyboard. CPU spikes to 100% on one core and results in stalling. In contrast the React+Redux app I'm working on uses the local Controller/Component state method and mashing on the keyboard there gave ~20% CPU. I never would have imagined that Redux Form would lag on a desktop/laptop. I was more concerned that mobile performance would suffer. It's kind of impressive that a simple form can lag a desktop browser...
- lopatin 10y agoFor basic forms, where you're not doing something weird, why would intermediate form state need to live in Redux? Local React state seems best for that.
- davidjnelson 10y agoAre there any cons to this approach? For me, having to implement setstate manually, not having full undo/redo/time travel debugging as an option/not being able to rehydrate the app from any state snapshot, along with the cognitive overhead of keeping state in sync in two places, one of which is mutable, are the big downsides.
- brentm 10y agoI agree with this. I've tried redux-form and just manually handling it with Redux but letting the form data live in the form's component state felt the most clean to me.
- acemarke 10y agoFirst: Redux is _not_ dogmatic about putting every last bit of your state into Redux. It is entirely up to you how much or how little goes into Redux. (This question comes up all the time, which is why I added it the the Redux FAQ [0] ). So yes, there are absolutely times when it makes sense to keep data, such as frequent user input updates, in local component state, and only dispatch an action later. In fact, a while back I put together a wrapper component that does exactly that [1]. Made a few tweaks since then that I haven't added to the proof-of-concept in the gist, but the basic idea is there. I do have a number of articles on React and forms in my React/Redux links list [2], but at the moment I don't think any of them specifically deal with Redux usage. Might be interesting to look through some of the apps listed in my real-world Redux apps list [3] - the Jenkins UI and Wordpress Admin Page apps might be relevant. I will say that while Redux Form [4] is probably the most widely used Redux form logic library at the moment, React Redux Form [5] is another option that looks good. In fact, the current Redux Form 6.0 beta API is heavily inspired by RRF's API. My Redux addons catalog also has a page listing a number of other options of varying kinds [6] (none of which I've used myself, btw, just catalogued). All that said, yeah, would be great if someone were to write up a larger, more in-depth article about dealing with forms. [0]: http://redux.js.org/docs/FAQ.html#organizing-state-only-redux-state http://redux.js.org/docs/FAQ.html#organizing-state-only-redu... [1]: https://gist.github.com/markerikson/554cab15d83fd994dfab https://gist.github.com/markerikson/554cab15d83fd994dfab [2]: https://github.com/markerikson/react-redux-links/blob/master/react-redux-architecture.md#react-and-forms https://github.com/markerikson/react-redux-links/blob/master... [3]: https://github.com/markerikson/redux-ecosystem-links/blob/master/apps-and-examples.md https://github.com/markerikson/redux-ecosystem-links/blob/ma... [4]: https://github.com/erikras/redux-form https://github.com/erikras/redux-form [5]: https://github.com/davidkpiano/react-redux-form https://github.com/davidkpiano/react-redux-form [6]: https://github.com/markerikson/redux-ecosystem-links/blob/master/forms.md https://github.com/markerikson/redux-ecosystem-links/blob/ma...
- Renner1 10y agoI agree with your point and disagree with redux-form being a valid solution. redux-form creates a very restricted and crippled API for getting form data into a redux state object and does so at the expense of the spirit of React's componentized model. Any redux-form state needs to be isolated under a special root object specifically for forms. You can't just mount some existing part of your state object into a form because of this. Not to mention redux-form properties have a whole bunch of other "glue" properties in addition to the actual value of the form. I question whether people use it in large scale production. This is one of the huge downfalls of redux. It makes some things easier, but it makes the most fundamental stuff (editing form fields) extremely contrived. This is the main reason I don't see react+redux as a true answer to the challenges of SPA development but a very rough, intermediate step which needs to be re-thought while putting into consideration the most common use cases.
- girvo 10y ago> I question whether people use it in large scale production. We tried to, and removed it within 4 weeks of development with it, for all of the reasons you mentioned. It conceptually doesn't map to our Redux model, and new developers struggled with it because of that. I ended up writing my own "wrapper" to do something similar, but to be honest for most of our form state it is handled within the components themselves (via this.state and friends) and only sent to Redux once validated. React's built-in state handling is still useful, specifically for these sorts of things.
- firasd 10y agoYour concerns about input events moving up and down the component tree seem misplaced. It’s what happens when you use React anyway (unless you’re only using local component state); putting these input values in the Redux store only makes things simpler. As for the fact that it changes the state and adds noise to the log… these seem like aesthetic judgments on your part. Why is changing an input “noise”? It’s an important part of the data on the page.
- davidjnelson 10y agoFor me the batched changes are useful, but single character changes can make the event log overly verbose.
- davidjnelson 10y agoFor the downvoter, you don't find single character changes overly verbose in the redux devtools monitor?
- deleted 10y ago[deleted]
- acemarke 10y agoNo, it's a pretty valid concern. If you assume controlled inputs, and you also tend towards putting all your state into Redux, that's exactly a use case issue you can see - every keystroke would, in theory, require a full round-trip through the store and back to the component, and also causing at least a `mapState` call and comparison for every other connected component along the way.
- firasd 10y agoHere is a GIF of me putting input state (and general form state) in the Redux store: http://i.imgur.com/QRDH1Sy.gifv http://i.imgur.com/QRDH1Sy.gifv Yes, if the keystrokes are not debounced it generates many actions. But my point is that concern about the ‘efficiency’ of moving events through components when using Redux is nothing compared to the byzantine way I had this implemented before using Redux. Trying to build forms in React without Redux or some other state solution, by just using setState and moving events and state up and down the component tree, will make you tear your hair out.
- waffleau 10y agoThis is something that tripped me up when I first started learning Redux too, and it would be great if there were more articles about what to do with the bits that don't really fit nicely into the model. My personal take is that the Redux state tree is for managing state that other components care about, i.e. if this changes, does something outside of this need to know? In the form example, there are few cases where we care about what is being typed as it is being typed (maybe autocomplete). We generally only care about the complete input. This could even be taken to the next level and we could say we only really care about the contents of a form once it has been submitted. To think about it another way,: what state would we like to keep if the page was refreshed? Many UI elements may contain state we don't really care about outside of the component, such as drop-down menus, accordions, etc. There are things which constitute global state, and there are things that really are just local state. Why make them global? Ultimately, the goal of Redux is to make reasoning about the state of an application easier, and to encourage better architecture. If pushing certain bits of state into the tree makes this harder, there's no reason to try to force it to fit the pattern. I'm sure there are good arguments for why everything should be in the global state, but I just haven't found it to be practically beneficial.
- ht85 10y agoMost of the time I don't feel like performance is an issue as long as all your components use PureRenderMixin. Unless it takes over 20-30ms to render, the difference is not noticeable. The problem as others have said is that it pollutes history, and that it is very CPU cycle hungry, bad for anything running on battery. Nowadays I tend to use onBlur instead. There are two scenarios: 1) The form is the only source of change for the data. In this case just update the global state onBlur. 2) Other things affect the form value, so you need controlled input. In this case, onChange updates the local state. onBlur updates the global state and set the local state to null. Use `<input value={localStateValue !== null ? localStateValue : globalStateValue}/>`
- antjanus 10y agoWe use Redux where I work and we deal with a TON of forms, many of which are controlled completely separately from each other. Oh and it's an Angular 1 app and in production. Basically what I've learned is that you have to distinguish between global and local application state. Redux doesn't have to know EVERYTHING that's going on in the application. That means that when you're editing a piece of text, it depends on what you want from it. Are you showing word count in several places that aren't contextually related? (like a total word count up top on your page, and a local word count). If so, run it through Redux on every key down/key up event. Are you NOT using that information anywhere? Then skip Redux and pipe that edited text through only when a user hits "save". The entire point of Flux was to have one source of truth for shared data in your app. If you're not sharing information, it doesn't have to be shoved into Flux/Redux. The example the FB developers brought up was reading messages. You have like 5 places that unread message count shows up: the little chat bar on bottom if you haven't read a message from a recent contact, notification bar up top, chat sidebar, and left sidebar (I think). Doing anything in any of those places should trigger a change: unread count drops when you open a chatbox with a person that left you a message for instance. But if you're writing a message and you're looking at your character count (like on twitter when you're writing a tweet), that data doesn't need to be shared. It just stays in that textarea component. I hope that makes sense! :)
- stickperson 10y agoAutocomplete is another good example. Instead of having my autocomplete API call go through the whole dispatch -> reducer flow, I just update my component's state when I get a response.
- joshuacc 10y agoYay! Another person using Redux with Angular 1. I've found it's a surprisingly nice combination. :-)
- deleted 10y ago[deleted]
- davidkpiano 10y agoI'm working on it, I promise! I have been doing a LOT of work on forms in React and Redux, and have been putting all of my ideas into a library called React-Redux-Form: https://github.com/davidkpiano/react-redux-form https://github.com/davidkpiano/react-redux-form The premise is simple - your model state shouldn't be intertwined with your form state, and everything should be "vanilla Redux" -- that is, everything related to form state should be represented by actions and reducers, and not by some black-box API hidden inside a decorated component. Version 1.0 is still in the works, but promises a lot of things such as making it MUCH simpler to get up and running with configuring the Redux store for forms, and also making smart optimizations that greatly improve performance. My goal is to make forms as easy to implement as it was in Angular, and offer full flexibility to the developer to handle forms of various complexity.