Craig
Craig

Reputation: 18694

React OnChange for every field - is there a better way

I call an API, get a payload and load it into state. Eg:

Payload : {
   id: 1,
   firstName: 'Craig',
   surname: 'Smith',
   anotherField: 'test data',
   ....
}

(Note, there are around 20 fields in real life)

On my react screen, I have the fields to display this data. At the moment, for every field, I have an onChange function. So:

this.firstnameOnChange = this.firstnameOnChange.bind(this);

and then the function:

firstnameOnChange() { ....}

Is there a simpler pattern to maybe lessen the amount of methods I need to create? Some sort of generic OnChange event that takes a name, and the value, which can then be used to update the state?

I can bind to something like:

myOnChange(fieldName, value) {
 // Somehow find the 'fieldName' in the state and update it's value with 'value'
}

Is this a valid pattern? Or is there a better way? Or should I stick to separate OnChange methods for each field?

If I can go generic, how would I find the name of the field in the state to update?

Upvotes: 1

Views: 464

Answers (2)

Sivcan Singh
Sivcan Singh

Reputation: 1892

Since the state is an object that means you can update it's key and value. All you have to do is pass down the correct parameters to a generic update function which will update the state.

Here's one way you can do it: https://codesandbox.io/s/v382v6l483

Since your payload is an entry one level down, we'll be using the spread operator and spread out the payload object. Update the value that you need and finally returns the payload to setState function to update the state and rerender the component.

You can bind this function to each field and keep your state updated.

Read more here on handling events and binding functions: https://reactjs.org/docs/handling-events.html

Upvotes: 1

Sakhi Mansoor
Sakhi Mansoor

Reputation: 8102

No this is not recommended to write onChange for every field. You can write a generic onChange method like this:

handleChange= name => event => {
 this.setState({payload: {...this.state.payload, [name] : event.target.value}});
  }

for example you have an input like this :

 <Input onChange={this.handleChange('firstName')} placeholder="Please Enter" />

PS here we are invoking handleChange directly so we use currying means a new instance being created for every invocation. There is another approach by extract name form event.target and create a name attribute in your input. Then you don't need to pass input name explicitly.

Upvotes: 4

Related Questions