Philip Bell Philip Bell - 1 month ago 29
React JSX Question

React checkbox. DRY out onChange function to handle all checkboxes

In the following code I have two checkboxes. On-click, they change the state of the component to their respective values.

I am building a form that will need over 100 checkboxes and I don't want to write the "onChange" function for each checkbox.

Is there a way that I can write one OnChange function that will take a parameter, then set the state to that parameter?

I've tried many ways but this is still blocking me.

Thank you!



import React from 'react';

export default class InputSearch extends React.Component {
constructor(props) {
super(props);
this.state = {
inputInternship: '',
inputMidLevel: '',
};
this.handleSubmit = this.handleSubmit.bind(this);
this.onChangeInternship = this.onChangeInternship.bind(this);
this.onChangeMidLevel = this.onChangeMidLevel.bind(this);
}

handleSubmit(e) {
e.preventDefault();
this.props.getJobData(this.state);
}

onChangeInternship(e) {
this.setState({
inputInternship: !this.state.inputInternship,
});
this.state.inputInternship == false? this.setState({ inputInternship: e.target.value }) : this.setState({ inputInternship: '' })
}

onChangeMidLevel(e) {
this.setState({
inputMidLevel: !this.state.inputMidLevel,
});
this.state.inputMidLevel == false? this.setState({ inputMidLevel: e.target.value }) : this.setState({ inputMidLevel: '' })
}

render() {
return (
<div className="search-form">
<form onSubmit={this.handleSubmit}>

<input type="checkbox" value="level=Internship&" checked={this.state.inputInternship} onChange={this.onChangeInternship} /> Internship <br />
<input type="checkbox" value="level=Mid+Level&" checked={this.state.inputMidLevel} onChange={this.onChangeMidLevel} /> Mid Level <br />

<div>
<button
type="submit"
>Search
</button>
</div>
</form>
</div>
);
}
}




Answer

Here are few ways I use in my projects..


1. Every input has it's own method

This is exactly what you did in your example.


2. Single method to rule them all

How it works? You can pass pretty much anything you want to bind and it is available in method.

Event:

onChange={this._handleChange.bind(this, 'string', 12, true)}

Method:

_handleChange(first, second, third) {
    console.log(first)  // 'string'
    console.log(second) // 12
    console.log(third)  // true
}

Example:

<input 
    type="checkbox" 
    checked={this.state.checkboxes.intership} 
    onChange={this._handleChange(this, 'internship')} 
/>

<input 
    type="checkbox" 
    checked={this.state.checkboxes.mid} 
    onChange={this._handleChange(this, 'mid')} 
 />

Now you can deal with different state-s there:

// If you want to do something different with every checkbox
_handleChange(type) {
    if (type === 'internship') {
        doThis()
    }
    else if (type === 'mid') {
        doThat()
    }
}


// Universal way to change state
_handleChange(event, type) {
    const value = event.target.value

    this.setState({
        checkboxes: update(this.state.checkboxes, {
            [type]: {
                '$set': value
            }
        })
    })
}

You'll need react-addons-update to use update().


3. Pass states to parent component

You can use parent component as controller to clean up your components or store all the state in one place (necessary for forms with lots of inputs). Read more about that.