Як користуватися перемикачами в ReactJS?


203

Я новачок у 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>.
Оріол

1
чи не повинні радіо кнопки мати однакові імена з різними значеннями для роботи?
pgee70

Відповіді:


209

Будь-які зміни в надання повинні бути змінені з допомогою stateабо props( реагують док ).

Отже, тут я реєструю подію введення, а потім змінюю на 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


3
Це було дуже корисно. Дякую. Те, що я не розумію, це біт }, this);під самим </tbody>. Що це таке і що він робить? Я помітив, що без цього код виходить з ладу.
Хоуман

3
Це thisконтекст, переданий mapфункції . Це була редакція @FakeRainBrigand, хороший улов! Без цього ваша thisфункція у карті буде посилатися на той window, який поняття не має про що stateйдеться
ChinKang

8
Цей thisтрюк непотрібний, якщо ви використовуєте стрілку ES6 замість звичайної функції. Напр .: var resultRows = this.props.data.map((result) => { ... });Я згадую це лише тому, що реагенти зазвичай вже використовують певну форму транспіляції (для JSX), тому ES6 зазвичай недоступний.
Том

1
Використання двох функцій для отримання значень перемикачів видається неоднозначним і непотрібним. Ви можете просто визначити одну функцію, можливоonInputChange (e) {this.setState({ [e.target.name]: e.target.value }); }
xplorer1

109

Ось найпростіший спосіб реалізації радіо кнопок у реагуючих 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

6
Я вірю .bind(this), щоразу створюватиме нову функцію. Це означає, що коли перевірка реагує на те, чи змінилося щось у віртуальному DOM, цей компонент завжди буде іншим і завжди потребуватиме повторного відтворення.
WoodenKitty

1
Нова функція кожного рендеру була б проблемою лише в тому випадку, якщо передати цю функцію як реквізит дочірньому компоненту. У такому випадку дочірній компонент, що приймає реквізит, може видаватись без потреби. Батьківський компонент буде добре.
Марк МакКелві

5
Для мене це працює лише один раз для натискання кожного радіо, яке має те саме ім’я. Наприклад, у мене є два радіо, які мають однакову nameпідтримку. Вони обоє загорнуті у діву, яка має onChangeобробник, як описано у цій відповіді. Я натискаю перше радіо, подія запускається. Я натискаю на друге радіо, подія запускається. Однак третій раз і далі жодна подія не проводиться. Чому?
Squrler

4
@Saahithyan У мене був однойменний атрибут, приєднаний до всіх радіостанцій. Виявилося, мені потрібно було поставити обробник onClick на входи радіо, а не обробник onChange. Це зробило трюк.
Squrler

3
Я погоджуюся з @Squrler - з onChange, ручка спрацьовує лише один раз для кожної з перемикачів, що входять до розділу div. З onClick він працює декілька разів. Не впевнений, чому це порівняно з вашим фрагментом ...
JESii

25

Спираючись на те, що кажуть Документи React :

Обробка декількох входів. Коли вам потрібно обробити кілька керованих вхідних елементів, ви можете додати атрибут імені до кожного елемента та дозволити функції обробника вибрати, що робити, виходячи зі значення 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-альфа 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


20

Зробіть радіокомпонент як німий компонент і передайте реквізит від батьків.

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;

2
це легко перевірити, оскільки компонент скиду є чистою функцією.
Халід Азам

7

Тут просто ідея: коли мова заходить про радіовведення в 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
Це чудово. Дуже сухий і робить речі приємними. Я б використовував об'єкт для кожного варіанту, але це питання переваги, я думаю.
nbkhope

@nbkhope, якби мені довелося його переписати, я б також використовував об'єкт! :)
Арно

Перевірте цей рядок: checked={ this.state.gender === value }. Функціональних компонентів немає this.
Авраам Ернандес

6
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
Ваш код працює, але слід також трохи пояснити його
Рахул Шарма

Примітка : Не використовуйте preventDefault в обробник OnChange , оскільки він запобігає настройку перевірений на компонент DOM
AlexNikonov

2

Натискання перемикача має викликати подію, яка:

  1. виклики setState, якщо ви хочете, щоб знання про вибір були локальними, або
  2. викликає зворотний виклик, переданий зверху self.props.selectionChanged(...)

У першому випадку зміна стану призведе до повторного відображення, і ви можете це зробити
<td>chosen site name {this.state.chosenSiteName} </td>

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


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>
    )
  }
}

за винятком цього значення має встановлене за замовчуванням значення.


1

Я також заплутався в реалізації радіо, прапорці. Що нам потрібно, це прослухати подію зміни радіо, а потім встановити стан. Я зробив невеликий приклад вибору статі.

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


0

Хлопці з завантаження, ми робимо це так:


export default function RadioButton({ onChange, option }) {
    const handleChange = event => {
        onChange(event.target.value)
    }

    return (
        <>
            <div className="custom-control custom-radio">
                <input
                    type="radio"
                    id={ option.option }
                    name="customRadio"
                    className="custom-control-input"
                    onChange={ handleChange }
                    value = { option.id }
                    />
                    <label
                        className="custom-control-label"
                        htmlFor={ option.option }
                        >
                        { option.option }
                    </label>
            </div>
        </>
    )
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.