简体   繁体   中英

Collect checkbox values as an array React

I have a checkbox component, I want my user to be able to check multiple items, and then the items to be saved in the state as an array.

If I select a checkbox my handleChange function seems to set my array to undefined, I'm not sure if it's the way I am sending the data or If I've setup my checkbox wrong, I'm quite new to React.

My main component is

export default class MainForm extends Component {
    state = {
        eventFormats: []
    }

    handleChange = input => event => {
        this.setState({[input]: event.target.value})
        console.log(this.state)
    }

    render() {
        const eventFormat = {eventFormats: this.state.eventFormats}
                return <EventFormat
                    nextStep={this.nextStep}
                    handleChange={this.handleChange}
                    values={eventFormat}
        }
    }
}

My event form component

export default class EventFormat extends Component {
    state = {
        eventFormats: [
            {id: 1, value: 1, label: "Virtual", isChecked: false},
            {id: 2, value: 2, label: "Hybrid", isChecked: false},
            {id: 3, value: 3, label: "Live", isChecked: false},
        ]
    }

    saveAndContinue = (e) => {
        e.preventDefault()
    }

    render() {
        return (
            <Form>
                <h1 className="ui centered">Form</h1>
                <Form.Field>
                    {
                        this.state.eventFormats.map((format) => {
                            return (<CheckBox handleChange={this.props.handleChange} {...format} />)
                        })
                    }
                </Form.Field>
                <Button onClick={this.saveAndContinue}>Next</Button>
            </Form>
        )
    }
}

And finally my checkbox component

const CheckBox = (props) => {
    return (<Checkbox label={props.label} onChange={props.handleChange('eventFormats')}/>)
}

export default CheckBox

The error is in your handleChange function, which sets state to a dictionary while you said you want the checkbox's value to be added to the eventFormats array in the state.

export default class MainForm extends Component {
    state = {
        eventFormats: []
    }

    handleChange = input => event => {
        if (event.target.checked) {
            this.setState({eventFormats: this.state.eventFormats.concat([event.target.value])});
        } else {
            const index = this.state.indexOf(event.target.value);
            if (index === -1) {
                console.error("checkbox was unchecked but had not been registered as checked before");
            } else {
                this.setState({eventFormats: this.state.eventFormats.splice(index, 1);
            }
        }
        console.log(this.state)
    }

    render() {
        const eventFormat = {eventFormats: this.state.eventFormats}
                return <EventFormat
                    nextStep={this.nextStep}
                    handleChange={this.handleChange}
                    values={eventFormat}
        }
    }
}

There are a few things to fix:

this.setState({[input]: event.target.value})

this will always overwrite the array( eventFormats ) with event.target.value .

<CheckBox handleChange={this.props.handleChange} {...format} />

in the above line, you're passing all the properties in each format object

const CheckBox = (props) => {
    return (<Checkbox label={props.label} onChange={props.handleChange('eventFormats')}/>)
}

but here you're only using label and handleChange .


Here's a React StackBlitz that implements what you're looking for. I used <input type="checkbox" /> , you can replace this with the Checkbox component you want. See the console logs to know how the state looks after toggling any of the checkboxes.

Also, added some comments to help you understand the changes.

const Checkbox = ({ id, checked, label, handleChange }) => {
  return (
    <>
      <input
        type="checkbox"
        id={id}
        value={checked}
        // passing the id from here to figure out the checkbox to update
        onChange={e => handleChange(e, id)}
      />
      <label htmlFor={id}>{label}</label>
    </>
  );
};

export default class App extends React.Component {
  state = {
    checkboxes: [
      { id: 1, checked: false, label: "a" },
      { id: 2, checked: false, label: "b" },
      { id: 3, checked: false, label: "c" }
    ]
  };

  handleChange = inputsType => (event, inputId) => {
    const checked = event.target.checked;
    // Functional update is recommended as the new state depends on the old state
    this.setState(prevState => {
      return {
        [inputsType]: prevState[inputsType].map(iT => {
          // if the ids match update the 'checked' prop
          return inputId === iT.id ? { ...iT, checked } : iT;
        })
      };
    });
  };

  render() {
    console.log(this.state.checkboxes);
    return (
      <div>
        {this.state.checkboxes.map(cb => (
          <Checkbox
            key={cb.id}
            handleChange={this.handleChange("checkboxes")}
            {...cb}
          />
        ))}
      </div>
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM