简体   繁体   English

如何在 reactjs 的一个组件中处理多个单选按钮组?

[英]How to handle multiple radio button groups in one component in reactjs?

I'm trying to send list of selected radio button ids from multiple radio button groups on clicking send button,我正在尝试在单击发送按钮时从多个单选按钮组中发送选定单选按钮 ID 的列表,

My problem: I am getting selected radio button from backend, then I should be able to change the radio button and send back to backend.我的问题:我从后端获得选中的单选按钮,然后我应该能够更改单选按钮并发送回后端。 but when I try to change the radio button it is not working.但是当我尝试更改单选按钮时它不起作用。

What I did not understand: How to handle the on change function, normally on change we can change the state but to change the state on load we should grab the values radio buttons.我不明白的是:如何处理更改 function,通常更改时我们可以更改 state 但要更改 state 加载时我们应该获取值。 Finally I got struck here, not understanding how to move forward.最后我被击中了,不知道如何前进。

Here is the wireframe and code snippet:这是线框图和代码片段:

线框

 function CardsList(props) { const cards = props.cards; return ( <div> {cards.map((card, idx) => ( <div> {card.cardName} { card.options.map((lo,idx) => ( <li key={idx}> <input className="default" type="radio" name={card.cardName} checked={lo.selected} />)) } <div> ))} </div> ); } //array of cards coming from the backend const cards = [ {cardName:'card1',options:[{radioName:'card1-radio1',selected:'true'}, {radioName:'card1-radio2',selected:'false'}]}, {cardName:'card2',options:[{radioName:'card2-radio1',selected:'true'}, {radioName:'card2-radio2',selected:'false'}]} ]; ReactDOM.render( <CardsList cards={cards} />, document.getElementById('root') );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"></div>

The reason why you can't change them is because of their current checked state which you are setting here: 您无法更改它们的原因是您在此处设置的当前已检查状态:

<input
  className="default"
  type="radio"
  name={card.cardName}
  checked={lo.selected}
/>

An approach I have used for this exact scenario is storing the component's state (from the server) in my component's state ( this.state ), passing the state to the element: checked={this.state.isChecked} , and updating the element's state onClick . 我用于这个确切场景的方法是将组件的状态(来自服务器)存储在组件的状态( this.state )中,将状态传递给元素: checked={this.state.isChecked} ,并更新元素的状态onClick

Example: 例:

class CardsList extends Component {
  constructor(props){
    super(props);
    this.state = {isChecked: false};
    this.inputOnClick = this.inputOnClick.bind(this);
  }
  //fetch data from server
  fetchData(){
    fetch('/api')
      .then(res => res.json())
      //this will be our initial state
      .then(res => this.setState(res))
  }
  componentDidMount(){
    this.fetchData();
  }
  //change radio button state on click
  inputOnClick(e){
    e.preventDefault();
    //invert state value
    this.setState((prevState, props) => {isChecked: !prevState.isChecked});
  }
  render(){
    return (
      <input
        type="radio"
        checked={this.state.isChecked}
        onClick={this.inputOnClick}
       />
      )
   }
}

this answer may work with single radio button group , but i am facing problem with multiple radio buttons with in multiple radio button groups.if you see the array of cards , how does it know which radio button group it belongs to. 这个答案可能适用于单个单选按钮组,但我遇到多个单选按钮组中的多个单选按钮的问题。如果你看到卡阵列,它如何知道它属于哪个单选按钮组。

We can modify the state based on the radio button's name. 我们可以根据单选按钮的名称修改状态。

Let's save all of your cards in your component's state. 让我们将所有卡片保存在组件的状态中。 I know the cards are retrieved from the server and will be saved using setState but I am writing it like this for visual purposes. 我知道这些卡是从服务器中检索出来的,并且将使用setState保存,但我这样写是为了视觉目的。

this.state = {cards: [
  { cardName:'card1',
  options:[
    {radioName:'card1-radio1',selected:true},
    {radioName:'card1-radio2',selected:false}
   ]
  },
  { cardName:'card2',
    options:[
      {radioName:'card2-radio1',selected:true},
      {radioName:'card2-radio2',selected:false}
     ]
    }
]}

Now when we click on a radio button, we will use that radio button's name to update the state where it needs to be updated. 现在,当我们点击单选按钮时,我们将使用该单选按钮的名称来更新需要更新的状态。 Since React state needs to be immutable, we will create a deep copy of the state, modify it, and then set the state with it. 由于React状态需要是不可变的,我们将创建状态的深层副本,修改它,然后用它设置状态。

inputOnClick(e){
  e.preventDefault();
  var thisRadioBtn = e.target.name;
  //make a deep copy of the state
  const stateCopy = JSON.parse(JSON.stringify(this.state.cards));
  //go through state copy and update it
  stateCopy.forEach(card => {
    card.options.forEach(option => {
      if(option.radioName === thisRadioBtn){
        //invert value
        //make sure the values are booleans
        option.selected = !option.selected;
      }
    });
  });
  //update the components state
  this.setState({cards: stateCopy});
}

You can use an object as a lookup table that holds the group names as keys. 您可以将对象用作将组名称保存为键的查找表。
On each change you will need to find the relevant group with the relevant option and set the new state accordingly. 在每次更改时,您都需要找到具有相关选项的相关组,并相应地设置新状态。

Important! 重要! - one thing to notice here, is that i changed the type of the selected property from a String to a Boolean . - 这里需要注意的一点是,我将selected属性的类型从String更改为Boolean this will let me handle the conditions like this: 这将让我处理这样的条件:

<input checked={option.selected} />

If you can't change it to a Boolean then you will need to handle the condition like this: 如果你不能将它改为Boolean那么你需要处理这样的条件:

<input checked={option.selected === 'true'} />

Here is a running example: 这是一个运行的例子:

 //array of cards coming from the backend const data = [ { cardName: 'card1', options: [{ radioName: 'card1-radio1', selected: true }, { radioName: 'card1-radio2', selected: false }] }, { cardName: 'card2', options: [{ radioName: 'card2-radio1', selected: true }, { radioName: 'card2-radio2', selected: false }] } ]; class CardsList extends React.Component { constructor(props) { super(props); this.state = { cards: [] }; } componentDidMount() { setTimeout(() => { // mimic an async server call this.setState({ cards: data }); }, 1000); } onInputChange = ({ target }) => { const { cards } = this.state; const nexState = cards.map(card => { if (card.cardName !== target.name) return card; return { ...card, options: card.options.map(opt => { const checked = opt.radioName === target.value; return { ...opt, selected: checked } }) } }); this.setState({ cards: nexState }) } onSubmit = () => { console.log(this.state.cards) }; render() { const { cards } = this.state; return ( <div> { cards.length < 1 ? "Loading..." : <div> {cards.map((card, idx) => ( <ul> {card.cardName} { card.options.map((lo, idx) => { return <input key={idx} type="radio" name={card.cardName} value={lo.radioName} checked={!!lo.selected} onChange={this.onInputChange} /> }) } </ul> )) } < button onClick={this.onSubmit}>Print Cards</button> </div> } </div> ); } } ReactDOM.render(<CardsList />, document.getElementById('root')); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"></div> 

In June 2022, I'm facing a similar issue with you.在 2022 年 6 月,我遇到了与您类似的问题。 My solution is just add tag <form> on both sections with no OnSubmit or action on it.我的解决方案是在两个部分都添加标签<form> ,而无需对其进行 OnSubmit 或操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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