Как использовать переключатели в ReactJS?

120

Я новичок в ReactJS, извините, если это звучит. У меня есть компонент, который создает несколько строк таблицы в соответствии с полученными данными.

Каждая ячейка внутри столбца имеет флажок радио. Следовательно, пользователь может выбрать один из site_name и один address из существующих строк. Выбор будет показан в нижнем колонтитуле. И вот где я застрял.

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, которого я совершенно не хватает? Большое спасибо

  • 3
    элементы input не имеют содержимого. Поэтому <input>content</input> не имеет смысла и недопустим. Вы можете захотеть <label><input />content</label> .
  • 0
    радиокнопки не должны иметь одинаковые имена с разными значениями для работы?
Теги:

8 ответов

126
Лучший ответ

Любые изменения в рендеринге должны быть изменены с помощью state или props (реакция doc).

Итак, здесь я регистрирую событие ввода, а затем изменяю 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

  • 2
    Это было очень полезно. Благодарю. То, что я не понимаю, это бит }, this); только под </tbody> . Что это такое и что оно делает? Я заметил без этого код вылетает.
  • 3
    this контекст передается на map функцию . Это было редактирование @FakeRainBrigand, хороший улов! Без него функция this в карте будет ссылаться на window , которое не имеет представления о state
Показать ещё 1 комментарий
66

Вот простейший способ реализации радиокнопки в реакции 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>

Edited

Вы можете использовать функцию стрелки вместо привязки. Замените вышеуказанный код как

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

Для значения по умолчанию используйте defaultChecked, как этот

<input type="radio" value="MALE" defaultChecked name="gender"/> Male
  • 5
    Я считаю, что .bind(this) будет создавать новую функцию каждый раз. Это означает, что когда реагируют проверки, чтобы увидеть, изменилось ли что-либо в виртуальной DOM, этот компонент всегда будет другим и всегда нуждается в повторном рендеринге.
  • 1
    Новая функция на каждом рендере будет проблемой только в том случае, если передать эту функцию в качестве подпорки дочернему компоненту. В этом случае дочерний компонент, получающий реквизиты, может рендериться без необходимости. Родительский компонент будет в порядке.
Показать ещё 9 комментариев
12

Сделайте радио компонент как тупой компонент и передайте реквизит от родителя.

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;
  • 1
    это легко проверить, так как компонент дампа является чистой функцией.
  • 1
    Спасибо за ответ, это должна быть "тупая" составляющая, я думаю.
4

Основываясь на том, что React Docs говорят:

Обработка нескольких входов. Когда вам нужно обработать несколько контролируемых элементов ввода, вы можете добавить атрибут 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;

РЕДАКТИРОВАТЬ:

С версией 16.7-alpha React есть предложение для чего-то, называемого 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

4

Просто идея здесь: когда речь идет о радиовводах в 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>
  • 1
    Это замечательно. Очень сухой и делает вещи приятными. Я бы использовал объект для каждой опции, но это вопрос предпочтений, я думаю.
  • 0
    @nbkhope, если бы мне пришлось переписать его, я бы тоже использовал объект! :)
2

Я тоже запутался в радио, реализация флажка. Нам нужно, прослушать событие изменения радио, а затем установить состояние. Я сделал небольшой пример выбора пола.

/*
 * A simple React component
 */
class App extends React.Component {
  constructor(params) {
     super(params) 
     // initial gender state set from props
     this.state = {
       gender: this.props.gender
     }
     this.setGender = this.setGender.bind(this)
  }
  
  setGender(e) {
    this.setState({
      gender: e.target.value
    })
  }
  
  render() {
    const {gender} = this.state
    return  <div>
        Gender:
        <div>
          <input type="radio" checked={gender == "male"} 
onClick={this.setGender} value="male" /> Male
          <input type="radio" checked={gender == "female"} 
onClick={this.setGender} value="female"  /> Female
        </div>
        { "Select Gender: " } {gender}
      </div>;
  }
}

/*
 * Render the above component into the div#app
 */
ReactDOM.render(<App gender="male" />, 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>
2

Нажатие на радиокнопку должно инициировать событие, которое:

  • вызывает setState, если вы хотите, чтобы знание выбора было локальным, или
  • вызывает обратный вызов, который был передан сверху self.props.selectionChanged(...)

В первом случае изменение состояния приведет к повторной визуализации, и вы можете сделать <td>chosen site name {this.state.chosenSiteName} </td>

во втором случае, источник обратного вызова обновит все, чтобы убедиться, что в строке, ваш экземпляр SearchResult будет выбранSiteName и selectedAddress, установленный в нем реквизитами.

1

Чтобы построить 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>
    )
  }
}

за исключением того, что это значение будет иметь значение по умолчанию.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню