在 React 中设置单选按钮值

Posted

技术标签:

【中文标题】在 React 中设置单选按钮值【英文标题】:Set radio button value in React 【发布时间】:2021-03-07 09:23:11 【问题描述】:

我正在制作一个带有单选按钮的简单反应应用程序。

这里有一个可用的默认数据,例如,

const defaultData = [ ContactMode: 3 ,  ContactMode: 2 ,  ContactMode: 2 ];

要求:

-> 需要迭代这个defaultData 并在每一行中指定它们各自的ContactMode 模式。

工作片段:

const  useState  = React;

const App = () => 
  const [formValue, setFormValue] = useState(
    ContactMode: 1
  );

  const defaultData = [ ContactMode: 3 ,  ContactMode: 2 ,  ContactMode: 2 ];

  const handleInputChange = (e, index) => 
    const  name, value  = event.target;
    setFormValue(
      ...formValue,
      [name]: value
    );
  ;

  const submitData = () => 
    console.log(formValue);
  ;

  return (
    <div>
      <form>
        defaultData.map((item, index) => 
          return (<React.Fragment>
            <label> Contact Mode </label>
            <input
              type="radio"
              name="ContactMode"
              checked=item.ContactMode == 1
              value=1
              onChange=(event) => handleInputChange(index, event)
            />" "
            Email
            <input
              type="radio"
              name="ContactMode"
              checked=item.ContactMode == 2
              value=2
              onChange=(event) => handleInputChange(index, event)
            />" "
            Text
            <input
              type="radio"
              name="ContactMode"
              checked=item.ContactMode == 3
              value=3
              onChange=(event) => handleInputChange(index, event)
            />" "
            Both
            <br />
            <br />
            <button type="button">
               Save
             </button>
            <br />
            <br />
            <br />
          </React.Fragment>);
        )
      </form>
    </div>
  );
;

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

预期输出:

Contact Mode  Email Text Both (Checked)

Contact Mode  Email Text(Checked) Both

Contact Mode  Email Text(Checked) Both

注意:我无法修改名称属性name="ContactMode".. 原因是我每行也有单独的保存按钮,单击该保存按钮时,特定行将被保存..并且每一行都应该有name="ContactMode" ..

编辑:

由于我的问题不清楚我想要实现的目标,我将在此处提供整个代码。

->我有一个步进表单,其中第 2 步是就业部分,默认情况下我有要设置到表单中的值,

const dynamicData = [
  
    EmploymentID: 1,
    companyName: 'Company One',
    designation: 'Designation One',
    ContactMode: 3,
  ,
  
    EmploymentID: 2,
    companyName: 'Company two',
    designation: 'Designation One',
    ContactMode: 2,
  ,
];

->useEffecthook 里面我设置了表单值,

  React.useEffect(() => 
    setExpanded(0);
    setValue((prev) => 
      const companyDetails = [...dynamicData];
      return  ...prev, companyDetails ;
    );
  , []);

这里带有输入框的表单值被正确绑定,但是单选按钮的值没有被检查。

-> 有两个数据可用,但默认情况下第一个将展开,而第二个将在单击第一个下方的 Expand 按钮时打开。

->点击save按钮后,该特定对象(inputField)将与修改后的数据一起被控制台记录(仅用于测试)。

这里的 ISSUE 是,如果我们修改数据,那么一切正常,但单选单选属性并没有使项目被选中..(选中的指示不起作用)..

请转到下面给出的代码框中的第 2 步以查看问题。要查看第二项,请单击展开按钮..

请帮我在每一行设置默认单选按钮值。

【问题讨论】:

您将handleInputChange 定义为使用(e, index),但在UI 中您颠倒了handleInputChange(index, event) 的顺序。你的defaultData 也有两个 ContactMode: 2 而没有 ContactMode: 1 ,也许这是故意的。正如@vkvkvkv 指出的那样,在所有无线电输入中使用相同的name 属性会将它们全部放在同一个无线电组中,并且只能有一个选定的无线电组值。 您是否可以控制输入的映射方式?你能分享更多关于每个按钮如何保存特定行的信息吗?行是如何识别的?保存的数据是什么?我有一个想法,但这取决于您对这些问题的回答才能真正了解您的要求/限制。 @DrewReese,我会尽快编辑问题,但在此之前我已经制作了一个代码框,其中包含我在这里为您提供的所有代码codesandbox.io/s/next-dynamic-testing-issue-forked-ebovz?file=/… .. 在此表格中,请转到第 2 步(就业详情) 查看我在哪里放置输入框和单选按钮.. @DrewReese,这是一种手风琴形式,因此将有 ExpandShrink 选项,这使得每个数据在点击时可展开 Expand .. @DrewReese,请查看相关编辑以更好地理解您在上述评论中提到的问题。 【参考方案1】:

在您的沙箱中,我能够让单选按钮工作

    为每个映射的无线电组提供唯一的name 更新更改处理程序以唯一处理ContactMode 属性。

更新无线电组以使用当前映射的索引,以使它们在所有映射的组中唯一。

<div className="form-group col-sm-4">
  <label className="inline-flex items-center mr-6">
    <input
      type="radio"
      className="form-radio border-black"
      name=`ContactMode-$index` // <-- append index to name
      value=1
      checked=inputField.ContactMode === 1 // <-- use strict "==="
      onChange=(event) => handleInputChange(index, event)
    />
    <span className="ml-2">Email</span>
  </label>
</div>
<div className="form-group col-sm-4">
  <label className="inline-flex items-center mr-6">
    <input
      type="radio"
      className="form-radio border-black"
      name=`ContactMode-$index`
      value=2
      checked=inputField.ContactMode === 2
      onChange=(event) => handleInputChange(index, event)
    />
    <span className="ml-2">Text</span>
  </label>
</div>
<div className="form-group col-sm-4">
  <label className="inline-flex items-center mr-6">
    <input
      type="radio"
      className="form-radio border-black"
      name=`ContactMode-$index`
      value=3
      checked=inputField.ContactMode === 3
      onChange=(event) => handleInputChange(index, event)
    />
    <span className="ml-2">Both</span>
  </label>
</div>

handleInputChange中添加一个case来专门处理ContactMode

const handleInputChange = (index, event) => 
  const  name, value  = event.target;
  if (name === 'designation' && !isLettersOnly(value)) 
    return;
  

  if (name.startsWith('ContactMode'))  // <-- check name prefix
    setValue((prev) => (
      ...prev,
      companyDetails: prev.companyDetails.map((detail, i) =>
        i === index
          ? 
              ...detail,
              ContactMode: Number(value), // <-- store back under correct key, as number for string equality check
            
          : detail,
      ),
    ));
    return; // <-- return early so other state update is skipped!
  

  setValue((prev) => 
    const companyDetails = prev.companyDetails.map((v, i) => 
      if (i !== index) 
        return v;
      

      return  ...v, [name]: value ;
    );

    return  ...prev, companyDetails ;
  );
;

【讨论】:

很棒的解决方案,我已经非常感谢您提供明确的解决方案,并且会一次又一次地说,因为您的工作非常感谢......非常感谢 Reese..【参考方案2】:

我认为是因为所有收音机都具有相同的名称属性 每个组都应该有不同的名称。 例如:

name = " ex1"
name = "ex2"
name = "ex3"

对于每个这样的新组到期名称。 如果你使用相同的名字,它会让一切都搞砸 另一个认为你是你 == 而不是 ===

item.ContactMode == 3

最好使用===

【讨论】:

不,我无法修改名称值,原因是每一行都有单独的保存按钮,单击该保存按钮时,将保存整行数据。有时我会得到类似的数据ContactMode : "3",所以只有我用过== .. 还编辑了个人保存的问题..但数据将来自像const defaultData = [ ContactMode: 3 , ContactMode: 2 , ContactMode: 2 ];这样的api.. 我认为这里唯一可能的方法是使用不同的名称【参考方案3】:

@TalOrlanczyk 的回答是正确的。您总共打印了 9 个单选按钮,并且在 name 属性中都具有相同的值。所以从技术上讲,它就像一个带有 9 个单选按钮的单选组,这意味着单选组只能接受一个值。 我运行了你的代码,它只在第 3 行选择了“文本”。

如果您尝试拥有 3 个单独的行(无线电组),您需要尝试以下操作:

<input
    type="radio"
    name="ContactMode"+index
    checked=item.ContactMode == 1
    value=1
    onChange=(event) => handleInputChange(index, event)
/>" "
Email
<input
    type="radio"
    name="ContactMode"+index
    checked=item.ContactMode == 2
    value=2
    onChange=(event) => handleInputChange(index, event)
/>" "
Text
<input
    type="radio"
    name="ContactMode"+index
    checked=item.ContactMode == 3
    value=3
    onChange=(event) => handleInputChange(index, event)
/>" "

尝试并重新运行您的代码

【讨论】:

我已经更新了这个问题,说我不能修改name 属性,因为我在每一行都有单独的保存,所以数据将在每一行中提交。但是当我收到数据时,我在数组defaultData 中得到它,我需要对其进行迭代并分配每个选定的单选按钮值..【参考方案4】:

您的代码中有一些问题...

    每次组件返回时,.map 都会在 defaultData 上调用。因此没有映射到状态。

    如果您希望每次迭代都使用相同的名称,那么您需要为每次迭代使用 &lt;form&gt;,否则所有单选按钮将组合在一起,因此只有最后一个单选按钮显示为已标记。

    最好使用=== 而不是==

我修改了你的代码,defaultData 用于初始化状态。

const  useState  = React;


  const defaultData = [ ContactMode: 3 ,  ContactMode: 2 ,  ContactMode: 2 ];

const App = () => 

  const [formValue, setFormValue] = useState([...defaultData]);

  const handleInputChange = (index, e) => 
    const  name, value  = e.target;

    const newFormValue = [...formValue];
    newFormValue.splice(index,1,[name]: value);
    
    setFormValue(newFormValue);
  ;

  const submitData = () => 
    console.log(formValue);
  ;

  return (
    <div>
        formValue.map((item, index) => 
          return (<form>
            <label> Contact Mode </label>
            <input
              type="radio"
              name="ContactMode"
              checked=Number(item.ContactMode) === 1
              value=1
              onChange=(event) => handleInputChange(index, event)
            />" "
            Email
            <input
              type="radio"
              name="ContactMode"
              checked=Number(item.ContactMode) === 2
              value=2
              onChange=(event) => handleInputChange(index, event)
            />" "
            Text
            <input
              type="radio"
              name="ContactMode"
              checked=Number(item.ContactMode) === 3
              value=3
              onChange=(event) => handleInputChange(index, event)
            />" "
            Both
            <br />
            <br />
          </form>);
        )
        <button type="button" onClick=submitData>
          " "
          Submit" "
        </button>
    </div>
  );
;

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

【讨论】:

我已经用真实的应用程序问题和真实的应用程序示例编辑了我的问题..请通过它..

以上是关于在 React 中设置单选按钮值的主要内容,如果未能解决你的问题,请参考以下文章

AngularJs - 在表格中设置单选按钮值

如何在jframe中的jpanel中设置单选按钮?

如何在引导表中设置单选按钮或复选框的样式?

在顺风 css 示例中设置单选按钮样式不起作用

如何在选中的自定义元框中设置单选按钮?

HTMLHTML 注册表单案例 ① ( 表格设置 | 设置表格位置和大小 | 设置表格标题 | 表单设置 | 表格中设置单选按钮 )