This type of behavior might be best managed by a library like Redux. With Redux, you could have a reducer that would track the state of each checkbox independently while still having knowledge of the state of the entire checkbox group.
For example, you could have a component with a render() method that derives the checked attribute from your Redux store.
render() {
// grab the checked attribute from your Redux store
// typically, you access the store via props using Provider
// pass each checkbox an id from the parent, and use this as a key
// to find its checked value in the store
let checked = this.props.store[this.props.checkboxId];
<input id={this.props.checkboxId} className='checkbox' type='checkbox' onChange={this.onChangeHandler} checked={checked} />
<label className='checkboxLabel' htmlFor={this.props.checkboxId}>{this.props.text}</label>
}
Your store and reducer would look something like this:
const initialState = {
checkbox1: false,
checkbox2: false,
checkbox3: false
};
const store = (state = initialState, action) => {
switch (action.type) {
case ('UPDATE_CHECKBOX'):
switch (action.payload.checkboxId) {
case 'checkbox1':
return Object.assign({}, state, {
checkbox1: action.payload.checked
});
case 'checkbox2':
return Object.assign({}, state, {
checkbox2: action.payload.checked
});
case 'checkbox3':
return Object.assign({}, state, {
checkbox3: action.payload.checked
});
default:
return state;
default:
return state;
}
Then in your component, the onChangeHandler just dispatches an action that signals the reducer to update the checkbox group state.
onChangeHandler(event) {
// grab the id of the checkbox you want to update
let checkboxToUpdate = event.target.id;
// set the checked value to be the opposite of what it was
let checked = !this.props.store[event.target.id];
// dispatch an action to perform the update
this.props.dispatch(checkboxActions.updateCheckbox({ checkboxId: checkboxToUpdate, checked }));
}
The nice thing about this approach is that you can trigger the checked attribute to change in one checkbox if another is clicked. For example, if we change our reducer like so:
const store = (state = initialState, action) => {
switch (action.type) {
case ('UPDATE_CHECKBOX'):
switch (action.payload.checkboxId) {
case 'checkbox1':
return Object.assign({}, state, {
checkbox1: action.payload.checked,
checkbox2: true,
checkbox3: false
});
case 'checkbox2':
return Object.assign({}, state, {
checkbox2: action.payload.checked
});
case 'checkbox3':
return Object.assign({}, state, {
checkbox3: action.payload.checked
});
default:
return state;
case 'CLEAR_CHECKBOXES':
return Object.assign({}, state, {
checkbox1: false,
checkbox2: false,
checkbox3: false
});
default:
return state;
}
Here we dispatch 'UPDATE_CHECKBOX' when we click on checkbox1, setting checkbox2 to true for its checked attribute and checkbox3 to false. Essentially, we are controlling one checkbox's behavior on click of another! You could also have an action that would set all checkboes' checked attributes to false like CLEAR_CHECKBOXES above. I've left out most of the setup for actions and action-types here, but the Redux docs do a good job of walking you through how to set that up. Hope this helps!