Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto save form fields in react and redux

I have a parent component which is a form and it is connected to the store via redux by doing so:

// FormComponent
export default connect(mapStateToProps, mapDispatchToProps)(FormComponent);

Inside that form, I have a list of input attributes which are children components of a form:

  • Form Component
    • First Name Component
    • Last Name Component
    • Address Component

I have a requirement to save changes in any field to the server by making update API call by passing JSON object that contains all attributes as soon as the input loses focus.

the API call would be something like:

updatePersonInfo({firstname: 'new name', lastname: 'new name', address: 'new address' });

My idea is to pass PersonInfo object as props from Form component to all children component. Each child component will update one attribute from PersonInfo props and dispatch UPDATE_PERSONINFO action with updated PersonInfo object. But to do that, I need to connect all child component to store also:

// FirstNameComponent
export default connect(mapStateToProps, mapDispatchToProps(FirstNameComponent);

// LastNameComponent
export default connect(mapStateToProps, mapDispatchToProps)(LastNameComponent);

// AddressComponent
export default connect(mapStateToProps, mapDispatchToProps)(AddressComponent);

But my thinking that we should avoid using connect for performance reason. Also, I'm not convinced that I need 4 connectors to call one action.

What would be the best option to handle this scenario?

like image 601
Mhd Avatar asked Jul 12 '18 19:07

Mhd


People also ask

Should I store form data in Redux?

We specifically recommend that most form state probably shouldn't be kept in Redux. However, it's your app, so you should evaluate the specific use cases you need to deal with to determine the right approach.


2 Answers

For this problem I can offer a good trick that I learned a while ago, in these situations we should use container component's state for creating a controlled form component and update the state on every form change, by that you can always access your form data from state of the container component. (For example: because of implementing controlled component, we can always send form data that is available for us from container component's state to Redux by a save button or in situations like your case Focusing on another field).

So let's get started:

(1) you need to use a name attribute and an onChange for each input, like so:

<input 
  type='text'
  name={name}
  className='form-control'
  value={value}
  onChange={onChange}/>

(2) the onChange function is placed in your container component and it is passed down via props to your input component and looks like this:

  updateCourseState(e) {
    const field = e.target.name
    const _formData = {...this.state.formData}
    _formData[field] = e.target.value // (*)
    return this.setState({ formData: _formData}) // <= then update the state on every change
  }

In here (*) by using precomputed dynamic variable names, we create a property for each input field in our temp _formData object and assign the target value of event that is been passed up, to it, after that we update the state.

(3) and finally you can now pass the state to redux when every you want, and as I read through your question you can use Refs() for that to keep track of when use focuses on another field you can check this tutorial on YouTube for that and when you change the focus, here is the place that you want to send your data to Redux.

like image 175
amdev Avatar answered Oct 07 '22 23:10

amdev


You can make the API call in each of the component directly to update only the corresponding attribute, so that you can avoid Redux for this.
Eg. updatePersonInfo({ firstname: 'new name' }).

Your API endpoint should be a PATCH method that updates only the fields that are in the payload (in the above example, it should only modify the field corresponding to firstname).

like image 45
Roy Wang Avatar answered Oct 08 '22 01:10

Roy Wang