【问题标题】:How do you toggle the checked value of a radio button in react using hooks?如何使用钩子在反应中切换单选按钮的选中值?
【发布时间】:2020-03-10 17:48:02
【问题描述】:

根据下面的示例,我从一些外部数据构建了一组单选按钮。除了aria-checked 属性外,它们按我的预期呈现和工作。单击一个单选按钮会切换选中的值,但当另一个被选中时,它仍然是true

如果我按顺序单击每个单选按钮,我最终会得到一个显示aria-checked="true" 的单选按钮列表,这显然不是最佳体验。

我不确定如何在选中另一个单选按钮时将选中的值切换回 false。

任何帮助都会很棒!

输入:

    const [isChecked, setIsChecked] = useState(false);

    <Input
        type={type}
        id={id}
        value={id}
        name={name}
        aria-label={label}
        aria-checked={isChecked}
        onChange={() => setIsChecked(!isChecked)}
    />
    <Label htmlFor={id}>{label}</Label>

用法:

    <fieldset>
        {someData.map(item => {
            return (
                <RadioButton
                    type="radio"
                    key={item.id}
                    id={item.id}
                    name={item.name}
                    label={item.label}
                />
            );
        })}
    </fieldset>

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    你可以试试这样的。

    const Radio = React.memo(function Radio({
      item,
      checked,
      onChange
    }) {
      console.log("rendering", item.label);
      return (
        <label>
          {item.label}
          <input
            type="radio"
            value={item.id}
            checked={checked}
            onChange={onChange}
          />
        </label>
      );
    });
    const RadioList = ({ items, value, onChange }) => (
      <div>
        {items.map(item => (
          <Radio
            item={item}
            key={item.id}
            checked={item.id === value}
            onChange={onChange}
          />
        ))}
      </div>
    );
    
    const App = ({ items }) => {
      const [value, setValue] = React.useState(items[0].id);
      const [v, setV] = React.useState(items[1].id);
      const onChange = React.useCallback(
        e => setValue(e.target.value),
        []
      );
      const onOther = React.useCallback(
        e => setV(e.target.value),
        []
      );
      return (
        <div>
          <RadioList
            items={items}
            value={value}
            onChange={onChange}
          />
          <RadioList
            items={items}
            value={v}
            onChange={onOther}
          />
        </div>
      );
    };
    //render app
    ReactDOM.render(
      <App
        items={[
          { id: "1", label: "one" },
          { id: "2", label: "two" },
          { id: "3", label: "three" },
          { id: "4", label: "four" }
        ]}
      />,
      document.getElementById("root")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    【讨论】:

    • 这看起来和我想要的完全一样!谢谢!
    【解决方案2】:

    这里有两点你应该改变。

    1. 当您在同一组下呈现单选按钮列表时,所有单选按钮的名称属性应该相同。因此,不要从someData 中读取名称属性,而是将相同的名称属性传递给每个按钮。或者在someData 中为每个对象保留相同的名称。

    2. 在那之后,我认为状态不应该在input 组件上,因为一旦您检查了单选,即使单击了某个单选按钮,您也永远不会更改它的值。您可以尝试在每个单选按钮上保持相同的名称属性。

    因此,解决方案可以是根据实际选择的收音机实际将选中的属性传递给 Input 组件。请检查以下代码:

    const RadioButton = ({ type, id, name, label, checked, onChange }) => {
    return (
        <>
            <input
                type={type}
                id={id}
                value={id}
                name={name}
                aria-label={label}
                aria-checked={checked}
                checked={checked}
                onChange={onChange}
            />
            <label htmlFor={id}>{label}</label>
        </>
    )
    

    }

    const RadioGroup = () => {
    const someData = [{
        id: 1,
        name: 'name',
        label: 'name 1'
    }, {
        id: 2,
        name: 'name',
        label: 'name 2'
    }, {
        id: 3,
        name: 'name',
        label: 'name 3'
    }];
    
    const [checkedValue, setIsChecked] = useState(1);
    
    return (
        <fieldset>
            {someData.map(item => {
                return (
                    <RadioButton
                        type="radio"
                        key={item.id}
                        id={item.id}
                        name="radioGroup"
                        label={item.label}
                        checked={checkedValue === item.id}
                        onChange={() => setIsChecked(item.id)}
                    />
                );
            })}
        </fieldset>
    )
    

    }

    【讨论】:

    • html components 生成需要对整个 document 唯一的 id 不是一个好主意。你确定一个 html 标签需要有一个 id 吗?此外,您在每次渲染时都传递了一个新引用作为道具的值,这意味着您将重新渲染每个收音机,包括那些没有改变的收音机。
    • 标签is not neededfor属性:Alternatively, you can nest the &lt;input&gt; directly inside the &lt;label&gt;, in which case the for and id attributes are not needed because the association is implicit:。我想这就是为什么你从来没有在React documentation 中这样做,因为他们知道组件应该做什么和不应该做什么。
    • 在任何 Radio 上触发 Change 实际上也会影响另一个 Radio,因为选中状态会发生变化。所以没有得到你说的第一点:Also you are passing a new reference as a value for a prop on every render, this means you'll re render every radio, including the ones that didn't change.
    • 如果您查看我的答案中的控制台日志,您会看到 2 个更改日志(一个未被选中,一个被选中)。不过有8台收音机。如果您将新引用作为 onChange 传递,则所有 8 个都将重新渲染。我确实在我的代码中传递了对 onChange 的引用,但我是在纯组件中进行的,而不是从父组件传递它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 2019-12-08
    相关资源
    最近更新 更多