简体   繁体   中英

React Form controlled by a Flux Store (Best practice?)

So I have a big component that would be my form:

<form>
 <FirstComponent value={this.state.firstValue}/>
 <SecondComponent value={this.state.secondValue}/>
 {more components here}
 <input type="submit" ... />
</form>

This form component is listening for a store that updates its values using firstAction , secondAction , etc.

Note: Component updates its state based on store.getState() that returns {firstValue: something, secondValue: something, etc}

So let's say my FirstComponent is an input:

<input type="text" value={this.props.value} 
   onChange={(e)=>this.props.firstAction(e.target.value)}
</input>

Ok, so the onChange fires the prop firstAction which is actually the Flux action that will update my store and make the form to re-render. I have two good things here, when user submits the form, I can check the value of FirstComponent in my store and I also control all my state from the parent component.

However, this onChange callback will call an action every time the user types one character (so it can produce a lot of calls therefore re-renders) <-- can this provoke serious performance issues?

Instead, I could use refs and when the user press the submit button, get this.refs.myFirstComponent.state ... and I will have the value too (that would be Uncontrolled Component ?) But this does not sound like a recommendation from the community.

So my question is, is the first approach I described above a good way to go? How can I optimize it? So a re-render that should only affect FirstComponent does not make SecondComponent and so on to re-render? Is shouldComponentUpdate the only way to go here?


Edit 1:

With the first approach I am facing a problem... I have an e2e test using WebdriverIO adding a value into the text field: http://webdriver.io/api/action/setValue.html

I don't know why but if I am trying to add the word "Testing" into the input, webdriver will only add the last letter. This problem is gone if not using state/store at all. However, if I have the state internally to my FirstComponent , something like:

<input type="text" value={this.state.value} 
   onChange={(e)=>this.setState({firstValue: e.target.value})}
   onBlur={()=>this.props.callback(this.state.firstValue)}
</input>

In this case, component seems to react faster while typing (only renders itself), and then, when user removes focus it updates the store. I have to say, I don't like this approach because it doesn't follow the pattern of take your state up (and I feel I am duplicating the state) BUT it seems to work faster and more important: My e2e test works. Any more ideas?

Your first approach (ie onChange fires flux action which updates the store and make your form re-render) seems like a good way to go. I've been using it like that and I've seen other people using it like that, too.

Regarding your following comment:

However, this onChange callback will call an action every time the user types one character (so it can produce a lot of calls therefore re-renders) <-- can this provoke serious performance issues?

Yes, I believe so. I once created a component that contains many other components along with some input fields. Whenever I typed a character in an input field, the whole component (with other components it includes and the input fields) got re-rendered, causing the performance problem. It was noticeable if I typed fast. You can actually verify it using https://facebook.github.io/react/docs/perf.html .

Anyway, how I got around the problem is, as you mentioned, by implementing shouldComponentUpdate() .

A small tip I'd like to mention is creating a custom <Input /> component that wraps around <input /> and implementing shouldComponentUpdate() (ie this.props.value !== nextProps.value || this.props.checked !== nextProps.checked ) That way, if you create a form component, for example, with many input fields (using the custom <Input /> ), only the input field that is changed gets re-rendered.

I'd love to see how other people approach this problem, too, though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM