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

9
我正在尝试在单击发送按钮时发送多个单选按钮组中所选单选按钮的ID列表, 我的问题: 我从后端获取了所选单选按钮,然后应该能够更改单选按钮并将其发送回后端。但是当我尝试更改单选按钮时它不起作用。 我没有理解的是: 如何处理on change函数,通常我们可以更改状态,但要在加载时更改状态,我们应该获取单选按钮的值。最后我被困在这里,不知道如何继续前进。
这是线框图和代码片段:

wireframe

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>

3个回答

4
您可以使用一个对象作为查找表,将组名作为键。
每次更改时,您需要找到相应组别和相关选项,并相应地设置新状态。 重要提示! - 这里需要注意的一件事是,我将selected属性的类型从String更改为Boolean。这将让我处理条件如下:
<input checked={option.selected} />

如果你不能将它改为一个“布尔值”,那么你需要像这样处理条件:
<input checked={option.selected === 'true'} />

这是一个实际的例子:

//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>


2

在2022年6月,我遇到了与你类似的问题。我的解决方案是在两个部分上都添加<form>标签,但没有OnSubmit或action。


2
你无法更改它们的原因是因为它们当前的选中状态是由你在这里设置的:
<input
  className="default"
  type="radio"
  name={card.cardName}
  checked={lo.selected}
/>

我曾经用过一种方法来处理这个情况,即将组件的状态(从服务器获取)存储在组件的状态中(this.state),将状态传递给元素:checked={this.state.isChecked},并在元素的 onClick 中更新元素的状态。
例如:
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}
       />
      )
   }
}

这个答案可能适用于单选按钮组,但我在处理多个单选按钮组内的多个单选按钮时遇到了问题。如果您查看卡数组,它如何知道它属于哪个单选按钮组。

我们可以根据单选按钮的名称修改状态。

让我们将所有卡保存在组件的状态中。我知道卡是从服务器检索并将使用 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}
     ]
    }
]}

现在当我们点击单选按钮时,我们将使用该单选按钮的名称来更新需要更新的状态。由于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});
}

这个答案可能适用于单选按钮组,但我在处理多个单选按钮组内的多个单选按钮时遇到了问题。如果您看到卡片数组,它如何知道它属于哪个单选按钮组。 - sravan ganji
如果我们有一个动态状态,并且我们不知道从后端会获得多少张卡,该怎么办? 我正在尝试,在我这边可能会发布一次,一旦我得到完美的答案。 - sravan ganji
只要你将获取的数据保存到状态中,就没问题了。 - JJJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接