最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React checkbox feature with only single selection - Stack Overflow

programmeradmin4浏览0评论

I want to figure out whether my code is wrong or a bug. I think there is no problem, but it does not work...

The code I used is:

class ItemView extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      options: [{
        id: 1,
        name: "Item 1"
      },
      {
        id: 2,
        name: "Item 2"
      }],
      optionSelected: 2
    }
  }

  toggleCheckbox(e) {
    console.log(e.target.id)
    if (this.state.optionSelected === e.target.id) {
      this.setState({
        optionSelected: undefined
      })
    } else {
      this.setState({ optionSelected: e.target.id })
    }
  }

  render() {
    return (
      <div className="container">
        <div className="row">
          <ItemList
            options={this.state.options}
            optionSelected={this.state.optionSelected}
            toggleCheckbox={(e) => this.toggleCheckbox(e)} />
        </div>
      </div>
    )
  }
}

const ItemList = ({ options, optionSelected, toggleCheckbox }) => {
  return (
    <div className="col s12">
      {
        options.map((option, index) => (
          <Item
            key={index}
            option={option}
            checked={(optionSelected === (index + 1) ? true : false)}
            toggleCheckbox={toggleCheckbox} />
        ))
      }
    </div>
  )
}

const Item = ({ option, checked, toggleCheckbox }) => {
  return (
    <div className="card">
      <div className="card-content">
        <p><label htmlFor={option.id}>
          <input 
            className="filled-in"
            type="checkbox"
            id={option.id}
            onChange={toggleCheckbox}
            checked={(checked ? "checked" : "")} />
          <span>{option.id}. {option.name}</span>
          </label></p>
      </div>
    </div>
  )
}

Code explaination:

React code, with materialize-css used.

It is a simple checkbox feature with multiple items, restricted to select only one item. So, if I check one of them, every item except for what I just selected will be unchecked automatically. If I uncheck what I just checked, every item will stay unchecked.

The core logic is: in <ItemList /> ponent, there is a conditional props that determines whether each item has to be checked or not. It pares the id, and hand in true or false into its children. That checked props is used in <Item /> ponent to set the checked attribute of <input>.

Strange thing is, as I set default choice in the initial state, when I just run the application, the check feature works as I expected. But if I click one of them, it does not work.

What is the problem of it?

I want to figure out whether my code is wrong or a bug. I think there is no problem, but it does not work...

The code I used is: https://codepen.io/cadenzah/pen/wvwYLgj?editors=0010

class ItemView extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      options: [{
        id: 1,
        name: "Item 1"
      },
      {
        id: 2,
        name: "Item 2"
      }],
      optionSelected: 2
    }
  }

  toggleCheckbox(e) {
    console.log(e.target.id)
    if (this.state.optionSelected === e.target.id) {
      this.setState({
        optionSelected: undefined
      })
    } else {
      this.setState({ optionSelected: e.target.id })
    }
  }

  render() {
    return (
      <div className="container">
        <div className="row">
          <ItemList
            options={this.state.options}
            optionSelected={this.state.optionSelected}
            toggleCheckbox={(e) => this.toggleCheckbox(e)} />
        </div>
      </div>
    )
  }
}

const ItemList = ({ options, optionSelected, toggleCheckbox }) => {
  return (
    <div className="col s12">
      {
        options.map((option, index) => (
          <Item
            key={index}
            option={option}
            checked={(optionSelected === (index + 1) ? true : false)}
            toggleCheckbox={toggleCheckbox} />
        ))
      }
    </div>
  )
}

const Item = ({ option, checked, toggleCheckbox }) => {
  return (
    <div className="card">
      <div className="card-content">
        <p><label htmlFor={option.id}>
          <input 
            className="filled-in"
            type="checkbox"
            id={option.id}
            onChange={toggleCheckbox}
            checked={(checked ? "checked" : "")} />
          <span>{option.id}. {option.name}</span>
          </label></p>
      </div>
    </div>
  )
}

Code explaination:

React code, with materialize-css used.

It is a simple checkbox feature with multiple items, restricted to select only one item. So, if I check one of them, every item except for what I just selected will be unchecked automatically. If I uncheck what I just checked, every item will stay unchecked.

The core logic is: in <ItemList /> ponent, there is a conditional props that determines whether each item has to be checked or not. It pares the id, and hand in true or false into its children. That checked props is used in <Item /> ponent to set the checked attribute of <input>.

Strange thing is, as I set default choice in the initial state, when I just run the application, the check feature works as I expected. But if I click one of them, it does not work.

What is the problem of it?

Share Improve this question asked Sep 19, 2019 at 9:26 cadenzahcadenzah 9783 gold badges11 silver badges30 bronze badges 1
  • I think you should try to use refs, IDs don't play nice with react – DaraJ Commented Sep 19, 2019 at 9:29
Add a ment  | 

3 Answers 3

Reset to default 2

You can check if the selected option is the checked one like this:

checked={optionSelected === option.id}

And then you simply get it into your input like this:

<input checked={checked} />

Also, make sure to change your state ids into strings (the DOM element id is of type string):

  options: [{
    id: '1',
    name: "Item 1"
  },
  {
    id: '2',
    name: "Item 2"
  }],
  optionSelected: '2'

https://codepen.io/AndrewRed/pen/gOYBVPZ?editors=0010

class ItemView extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      options: [{
        id: 1,
        name: "Item 1"
      },
      {
        id: 2,
        name: "Item 2"
      }],
      optionSelected: 2
    }
  }

  toggleCheckbox(e) {

    this.setState({
      optionSelected : e.target.id
    })
   }

  render() {
    return (
      <div className="container">
        <div className="row">
          <ItemList
            options={this.state.options}
            optionSelected={this.state.optionSelected}
            toggleCheckbox={(e) => this.toggleCheckbox(e)} />
        </div>
      </div>
    )
  }
}

const ItemList = ({ options, optionSelected, toggleCheckbox }) => {

  return (
    <div className="col s12">
      {
        options.map((option, index) => (
          <Item
            key={index}
            option={option}
            checked={(optionSelected === (index + 1) ? true : false)}
            toggleCheckbox={toggleCheckbox} 
            optionSelected = {optionSelected}
            />
        ))
      }
    </div>
  )
}

const Item = ({ option, checked, toggleCheckbox,optionSelected }) => {
  return (
    <div className="card">
      <div className="card-content">
        <p><label htmlFor={option.id}>
          <input 
            className="filled-in"
            type="checkbox"
            id={option.id}
            onChange={toggleCheckbox}
            checked={option.id == optionSelected ? "checked" : ""} />
          <span>{option.id}. {option.name}</span>
          </label></p>
      </div>
    </div>
  )
}

function tick() {
  ReactDOM.render(
    <ItemView />,
    document.getElementById('root')
  );
}

tick()

COPY PASTE AND RUN

e.target.id is a string while index is a number. When you do a === parison the type is also checked and these are not the same. This results in checked always being false after the initial state (which you set yourself as an int)

发布评论

评论列表(0)

  1. 暂无评论