如何在ReactJS中使用单选按钮?

311

我刚接触ReactJS,如果我的问题有些奇怪,请见谅。我有一个组件,根据收到的数据创建了几个表行。

每个列中的每个单元格都有一个单选框。因此,用户可以从现有行中选择一个site_name和一个地址。选择将显示在页脚中。这就是我卡住的地方。

var SearchResult = React.createClass({
  render: function () {
    var resultRows = this.props.data.map(function (result) {
      return (
        <tbody>
          <tr>
            <td>
              <input type="radio" name="site_name" value={result.SITE_NAME}>
                {result.SITE_NAME}
              </input>
            </td>
            <td>
              <input type="radio" name="address" value={result.ADDRESS}>
                {result.ADDRESS}
              </input>
            </td>
          </tr>
        </tbody>
      );
    });
    return (
      <table className="table">
        <thead>
          <tr>
            <th>Name</th>
            <th>Address</th>
          </tr>
        </thead>
        {resultRows}
        <tfoot>
          <tr>
            <td>chosen site name ???? </td>
            <td>chosen address ????? </td>
          </tr>
        </tfoot>
      </table>
    );
  },
});

在jQuery中,我可以这样做:$("input[name=site_name]:checked").val()来获取单选复选框的选择,并将其插入到第一个页脚单元格中。

但是肯定有一种Reactjs的方法,但我完全不知道。非常感谢


5
input 元素没有内容。因此,<input>content</input> 没有意义且无效。您可能需要使用 <label><input />content</label> - Oriol
4
单选按钮不必具有相同的名称,只需具有不同的值即可正常工作。 - pgee70
13个回答

293

任何渲染的更改都应通过 stateprops 进行更改 (react 文档)。

因此,我在此注册输入事件,然后更改 state,这将触发渲染并显示在页脚上。

var SearchResult = React.createClass({
  getInitialState: function () {
    return {
      site: '',
      address: '',
    };
  },
  onSiteChanged: function (e) {
    this.setState({
      site: e.currentTarget.value,
    });
  },

  onAddressChanged: function (e) {
    this.setState({
      address: e.currentTarget.value,
    });
  },

  render: function () {
    var resultRows = this.props.data.map(function (result) {
      return (
        <tbody>
          <tr>
            <td>
              <input
                type="radio"
                name="site_name"
                value={result.SITE_NAME}
                checked={this.state.site === result.SITE_NAME}
                onChange={this.onSiteChanged}
              />
              {result.SITE_NAME}
            </td>
            <td>
              <input
                type="radio"
                name="address"
                value={result.ADDRESS}
                checked={this.state.address === result.ADDRESS}
                onChange={this.onAddressChanged}
              />
              {result.ADDRESS}
            </td>
          </tr>
        </tbody>
      );
    }, this);
    return (
      <table className="table">
        <thead>
          <tr>
            <th>Name</th>
            <th>Address</th>
          </tr>
        </thead>
        {resultRows}
        <tfoot>
          <tr>
            <td>chosen site name {this.state.site} </td>
            <td>chosen address {this.state.address} </td>
          </tr>
        </tfoot>
      </table>
    );
  },
});

jsbin


4
非常有用,谢谢。我不明白的是</tbody>下面的那一段代码:}, this);它是什么,它是做什么的?我注意到没有它,代码会崩溃。 - Houman
4
“this”是传递给map函数的上下文。这是由@FakeRainBrigand编辑的,非常好的发现!如果没有它,在map函数中使用“this”将引用窗口(window),而它不知道“state”是什么。 - ChinKang
12
如果您使用ES6箭头函数而不是普通函数,那么这个this技巧就是不必要的。例如:var resultRows = this.props.data.map((result) => { ... }); 我提到它只是因为React开发者通常已经在使用某种形式的转译(用于JSX),因此ES6通常很容易实现。 - Tom
2
使用两个函数获取单选按钮的值似乎有歧义且不必要。您可以只定义一个函数,例如 onInputChange (e) {this.setState({ [e.target.name]: e.target.value }); } - xplorer1

177

这里是在React JS中实现单选按钮的最简单方式。

class App extends React.Component {
  
  setGender(event) {
    console.log(event.target.value);
  }
  
  render() {
    return ( 
      <div onChange={this.setGender.bind(this)}>
        <input type="radio" value="MALE" name="gender"/> Male
        <input type="radio" value="FEMALE" name="gender"/> Female
      </div>
     )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<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="app"></div>

编辑

您可以使用箭头函数代替绑定。将上述代码替换为

<div onChange={event => this.setGender(event)}>

要使用默认值,请使用 defaultChecked,如下所示:

<input type="radio" value="MALE" defaultChecked name="gender"/> Male

10
我相信.bind(this)每次都会创建一个新的函数。这意味着当React检查虚拟DOM中是否有任何更改时,该组件始终会有所不同,并且需要重新渲染。 - WoodenKitty
1
我同意这个答案,而不是被接受的答案。既然HTML已经处理了单选按钮状态,就没有理由将状态引入JavaScript中。 - PrimeLens
7
对我而言,这只适用于点击每个具有相同名称的单选框一次。例如,我有两个具有相同name属性的单选框。它们都包裹在一个具有描述中所述的 onChange 处理程序的 div 中。我单击第一个单选框,事件被触发。我单击第二个单选框,事件被触发。然而,第三次及以后就不会触发任何事件了。为什么? - Squrler
4
我之前将同一个名字属性附加在所有单选按钮上。结果发现我需要为单选按钮输入添加 onClick 处理程序,而不是 onChange 处理程序。这样就解决了问题。 - Squrler
4
我同意@Squrler的观点——使用onChange时,处理函数每个包含在div下的单选按钮只会触发一次。使用onClick则可以多次触发。不确定为什么与你的代码片段相比会出现这种情况... - JESii
显示剩余8条评论

45

根据React文档

处理多个输入。当您需要处理多个受控输入元素时,可以向每个元素添加name属性,并让处理程序函数根据event.target.name的值选择要执行的操作。

例如:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleChange = e => {
    const { name, value } = e.target;

    this.setState({
      [name]: value
    });
  };

  render() {
    return (
      <div className="radio-buttons">
        Windows
        <input
          id="windows"
          value="windows"
          name="platform"
          type="radio"
          onChange={this.handleChange}
        />
        Mac
        <input
          id="mac"
          value="mac"
          name="platform"
          type="radio"
          onChange={this.handleChange}
        />
        Linux
        <input
          id="linux"
          value="linux"
          name="platform"
          type="radio"
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

示例链接:https://codesandbox.io/s/6l6v9p0qkr

一开始,没有任何单选按钮被选中,所以this.state是一个空对象,但每当用户选择单选按钮时,this.state就会获得一个新属性,该属性的名称为输入的名称,其值为输入的值。然后可以轻松地检查用户是否选择了任何单选按钮,例如:

const isSelected = this.state.platform ? true : false;

编辑:

在 React 的 16.7-alpha 版本中,有一个名为“hooks”的提案。这使得您可以更轻松地执行此类操作:

在下面的示例中,函数组件中有两组单选按钮。它们仍然具有可控输入:

function App() {
  const [platformValue, plaftormInputProps] = useRadioButtons("platform");
  const [genderValue, genderInputProps] = useRadioButtons("gender");
  return (
    <div>
      <form>
        <fieldset>
          Windows
          <input
            value="windows"
            checked={platformValue === "windows"}
            {...plaftormInputProps}
          />
          Mac
          <input
            value="mac"
            checked={platformValue === "mac"}
            {...plaftormInputProps}
          />
          Linux
          <input
            value="linux"
            checked={platformValue === "linux"}
            {...plaftormInputProps}
          />
        </fieldset>
        <fieldset>
          Male
          <input
            value="male"
            checked={genderValue === "male"}
            {...genderInputProps}
          />
          Female
          <input
            value="female"
            checked={genderValue === "female"}
            {...genderInputProps}
          />
        </fieldset>
      </form>
    </div>
  );
}

function useRadioButtons(name) {
  const [value, setState] = useState(null);

  const handleChange = e => {
    setState(e.target.value);
  };

  const inputProps = {
    name,
    type: "radio",
    onChange: handleChange
  };

  return [value, inputProps];
}

工作示例:https://codesandbox.io/s/6l6v9p0qkr


26
将收音机组件变成哑组件,从父组件传递属性。
import React from "react";

const Radiocomponent = ({ value, setGender }) => ( 
  <div onChange={setGender.bind(this)}>
    <input type="radio" value="MALE" name="gender" defaultChecked={value ==="MALE"} /> Male
    <input type="radio" value="FEMALE" name="gender" defaultChecked={value ==="FEMALE"}/> Female
  </div>
);

export default Radiocomponent;

它易于测试,因为它是一个"哑组件"(纯函数)。


5
最好使用"checked"。我相当确定这是"defaultChecked"的错误用法。 - tekHedd
1
使用defaultChecked适用于未受控的React输入。当React更改defaultChecked属性的值时,未受控的输入不会发生变化。在此情况下,defaultChecked可能有效,因为当值属性更改时,整个组件都会重新渲染。 - Mnebuerquo

12

这里提供一个想法:在React中处理单选框输入时,我通常会以不同的方式呈现所有单选框,这与之前的答案有所不同。

如果这能帮助任何需要呈现大量单选按钮的人:

import React from "react"
import ReactDOM from "react-dom"

// This Component should obviously be a class if you want it to work ;)

const RadioInputs = (props) => {
  /*
    [[Label, associated value], ...]
  */
  
  const inputs = [["Male", "M"], ["Female", "F"], ["Other", "O"]]
  
  return (
    <div>
      {
        inputs.map(([text, value], i) => (
   <div key={ i }>
     <input type="radio"
              checked={ this.state.gender === value } 
       onChange={ /* You'll need an event function here */ } 
       value={ value } /> 
         { text }
          </div>
        ))
      }
    </div>
  )
}

ReactDOM.render(
  <RadioInputs />,
  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
这很棒。非常DRY,让事情变得很好。我会为每个选项使用一个对象,但我想这只是一种偏好。 - nbkhope
@nbkhope 如果我要重写它,我也会使用对象! :) - Arnaud
1
请检查这一行代码:checked={ this.state.gender === value }。函数组件中没有 this - Abraham
1
我会设置一个标签,而不是 <div key={ i }> - Juan Lanus

8
import React, { Component } from "react";

class RadionButtons extends Component {
  constructor(props) {
    super(props);

    this.state = {
      // gender : "" , // use this one if you don't wanna any default value for gender
      gender: "male" // we are using this state to store the value of the radio button and also use to display the active radio button
    };

    this.handleRadioChange = this.handleRadioChange.bind(this);  // we require access to the state of component so we have to bind our function 
  }

  // this function is called whenever you change the radion button 
  handleRadioChange(event) {
      // set the new value of checked radion button to state using setState function which is async funtion
    this.setState({
      gender: event.target.value
    });
  }


  render() {
    return (
      <div>
        <div check>
          <input
            type="radio"
            value="male" // this is te value which will be picked up after radio button change
            checked={this.state.gender === "male"} // when this is true it show the male radio button in checked 
            onChange={this.handleRadioChange} // whenever it changes from checked to uncheck or via-versa it goes to the handleRadioChange function
          />
          <span
           style={{ marginLeft: "5px" }} // inline style in reactjs 
          >Male</span>
        </div>
        <div check>
          <input
            type="radio"
            value="female"
            checked={this.state.gender === "female"}
            onChange={this.handleRadioChange}
          />
          <span style={{ marginLeft: "5px" }}>Female</span>
        </div>
      </div>
    );
  }
}
export default RadionButtons;

1
你的代码可以运行,但你也应该稍微解释一下。 - Rahul Sharma
1
请注意:在onChange处理程序中不要使用preventDefault,因为它会阻止将checked设置为DOM组件。 - Alexey Nikonov
我基本上使用了这种方法,但是我不得不切换到使用onClick处理程序。 - TimSC

7

以下是我使用过的内容。希望对你有所帮助。
首先定义变量。

const [variableName, setVariableName] = useState("");

接下来,我们需要实际的单选按钮。

<input
   type="radio"
   name="variableName"
   value="variableToCheck"
   onChange={(e) =>
   setVariableName("variableToCheck")
   }
   checked={variableName === "variableToCheck"}
/>

3

@Tomasz Mularczyk在他的回答中提到了React Hooks,但我想分享一个最近我用过仅使用useState Hook的解决方案。

function Radio() {
  const [currentRadioValue, setCurrentRadioValue] = useState()

  const handleRadioChange = (e) => {
    setCurrentValue(e.target.value);
  };

  return ( 
    <>
      <div>
        <input
          id="radio-item-1"
          name="radio-item-1"
          type="radio"
          value="radio-1"
          onChange={handleRadioChange}
          checked={currentRadioValue === 'radio-1'}
        />
        <label htmlFor="radio-item-1">Radio Item 1</label>
      </div>
      <div>
        <input
          id="radio-item-2"
          name="radio-item-2"
          type="radio"
          value="radio-2"
          onChange={handleRadioChange}
          checked={currentRadioValue === 'radio-2'}
        />
        <label htmlFor="radio-item-2">
          Radio Item 1
        </label>
      </div>
    </>
  );
}

2

在ChinKang提供的答案基础上,我有一个更加干燥的方法,并且使用es6语法:

class RadioExample extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      selectedRadio: 'public'
    };
  }

  handleRadioChange = (event) => {
    this.setState({
      selectedRadio: event.currentTarget.value
    })
  };

  render() {
    return (
      <div className="radio-row">
        <div className="input-row">
          <input
            type="radio"
            name="public"
            value="public"
            checked={this.state.selectedRadio === 'public'}
            onChange={this.handleRadioChange}
          />
          <label htmlFor="public">Public</label>
        </div>
        <div className="input-row">
          <input
            type="radio"
            name="private"
            value="private"
            checked={this.state.selectedRadio === 'private'}
            onChange={this.handleRadioChange}
          />
          <label htmlFor="private">Private</label>
        </div>
      </div>
    )
  }
}

除了这个选项默认会被勾选。


2
点击单选按钮应该触发一个事件,这个事件要么:
1. 调用setState,如果您只想让选择的知识局限于本地;或者 2. 调用从上面传递过来的回调函数self.props.selectionChanged(...) 在第一种情况下,状态的改变会触发重新渲染,您可以这样做: <td>已选择站点名称 {this.state.chosenSiteName} </td> 在第二种情况下,回调函数的来源将更新内容,以确保沿线,您的SearchResult实例将在其props中设置chosenSiteName和chosenAddress。

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