3

With a checkbox onChange event, how do I remove value from state array when unchecked in react?

State array:

this.state = { value: [] }

onChange function:

handleChange = event => {
    if (event.target.checked) {
        this.setState({
            value: [...this.state.value, event.target.value]
        });
    } else {
        this.setState({
            value: [this.state.value.filter(element => element !== event.target.value)]
        });
    }
};

Not sure exactly what the .filter() should be doing

1 Answer 1

7

You're very close, except:

  1. You need to remove the [] around your call to filter. filter returns an array. If you wrap that in [], you're putting the array inside another array, which you don't want (in this case).

    and

  2. Since you're updating state based on existing state, it's important to use the callback version of setState, not the version that directly accepts an object. State updates can be batched together, so you need to be sure you're dealing with the most recent version of the array.

So:

handleChange = ({target: {checked, value: checkValue}}) => {
//             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                 ^− destructuring to take the properties from the event,
//                    since the event object will get reused and we're doing
//                    something asynchronous below
    if (checked) {
        this.setState(({value}) => ({value: [...value, checkValue]}));
    } else {
        this.setState(({value}) => ({value: value.filter(e => e !== checkValue)}));
        //                                  ^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^−−− No [] around  this
    }
};

There are some situations where you'd get away with using this.state.value instead of using the callback (for instance, if you only update value in response to certain events), but you have to be sure you know which ones they are; it's simpler just to use the callback.


FWIW, since it has multiple values in it, if it were me I'd call the state property values (plural) rather than value, which would also mean we didn't have to rename the value from the event target in the destructuring above:

handleChange = ({target: {checked, value}}) => {
    if (checked) {
        this.setState(({values}) => ({values: [...values, value]}));
    } else {
        this.setState(({values}) => ({values: values.filter(e => e !== value)}));
    }
};
Sign up to request clarification or add additional context in comments.

7 Comments

Hey @T.J. Crowder, thanks for the answer :) You reckon the element !== event.target.value is ok too?
@js-learner - Yes, since you're directly storing the values of the checkboxes, so you're comparing like for like. Note the update, there's a second thing you probably want to do above.
Ahh fantastic, and totally makes sense, thank you so much :)
this.setState(({values}) => ({values: checked ? [...values, value] : values.filter(e => e !== value)}));
@DennisVash - It's value in the OP's original, which is what the first code block relates to; only values in the last code block suggesting changing the name of the state property.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.