Come usare i pulsanti di opzione in ReactJS?


204

Sono nuovo di ReactJS, scusate se questo suona male. Ho un componente che crea diverse righe di tabella in base ai dati ricevuti.

Ogni cella all'interno della colonna ha una casella di controllo radio. Quindi l'utente può selezionare uno site_namee uno addressdalle righe esistenti. La selezione deve essere indicata nel piè di pagina. Ed è qui che sono bloccato.

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

In jQuery ho potuto fare qualcosa di simile $("input[name=site_name]:checked").val()per ottenere la selezione di un tipo di casella di controllo radio e inserirla nella cella del primo piè di pagina.

Ma sicuramente ci deve essere un modo Reactjs, che mi manca del tutto? Grazie molto


3
inputgli elementi non hanno contenuto. Quindi <input>content</input>non ha senso ed è invalido. Si consiglia <label><input />content</label>.
Oriol,

1
i pulsanti di opzione non devono avere gli stessi nomi con valori diversi per funzionare?
pgee70,

Risposte:


209

Eventuali modifiche alla resa dovrebbero essere il cambiamento attraverso la stateo props( reagire doc ).

Quindi qui registro l'evento dell'ingresso, e poi cambio state, che attiverà il rendering da mostrare sul piè di pagina.

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
È stato molto utile. Grazie. Quello che non capisco è il bit }, this);appena sotto il </tbody>. Cos'è e che cosa fa? Ho notato senza che il codice si arresta in modo anomalo.
Houman,

3
Il thisè il contesto passato alla mapfunzione di . È stata la modifica di @FakeRainBrigand, buona cattura! Senza di essa la tua funzione thisnella mappa farà riferimento a window, che non ha idea di cosa si statetratti
ChinKang

8
Questo thistrucco non è necessario se si utilizza una freccia ES6 anziché una normale funzione. Ad esempio: var resultRows = this.props.data.map((result) => { ... });lo menziono solo perché i Reattori di solito usano già una qualche forma di transpilazione (per JSX), quindi ES6 è in genere a portata di mano.
Tom,

1
L'uso di due funzioni per ottenere i valori dei pulsanti di opzione appare ambiguo e non necessario. Potresti semplicemente definire una funzione, forseonInputChange (e) {this.setState({ [e.target.name]: e.target.value }); }
xplorer1

110

Ecco un modo più semplice di implementare i pulsanti di opzione in reatt 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>

Modificato

È possibile utilizzare la funzione freccia anziché l'associazione. Sostituisci il codice sopra come

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

Per un valore predefinito utilizzare defaultChecked, come questo

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

6
Credo .bind(this)che creerà una nuova funzione ogni volta. Ciò significa che quando reagisce controlla se qualcosa è cambiato nel DOM virtuale, questo componente sarà sempre diverso e avrà sempre bisogno di un nuovo rendering.
WoodenKitty

1
La nuova funzione su ogni rendering sarebbe un problema solo se passasse questa funzione come oggetti di scena a un componente figlio. In tal caso il componente figlio che riceve gli oggetti di scena potrebbe essere reso inutilmente. Il componente padre andrebbe bene.
Mark McKelvy,

5
Per me questo funziona solo una volta facendo clic su ogni radio che condivide lo stesso nome. Ad esempio, ho due radio che hanno lo stesso namesostegno. Sono entrambi avvolti in un div che ha il onChangegestore come descritto in questa risposta. Faccio clic sulla prima radio, viene generato un evento. Faccio clic sulla seconda radio, viene generato un evento. La terza volta e comunque non viene generato alcun evento. Perché?
Squrler,

4
@Saahithyan Avevo lo stesso attributo di nome associato a tutte le radio. Ho scoperto che dovevo mettere un gestore onClick agli ingressi radio invece di un gestore onChange. Questo ha funzionato.
Squrler,

3
Sono d'accordo con @Squrler - con onChange, la maniglia si attiva solo una volta per ciascuno dei pulsanti di opzione inclusi nel div. Con onClick, funziona più volte. Non so perché sia ​​paragonato al tuo frammento ...
GESii

25

Sulla base di ciò che dice React Docs :

Gestione di più ingressi. Quando è necessario gestire più elementi di input controllati, è possibile aggiungere un attributo name a ciascun elemento e lasciare che la funzione handler scelga cosa fare in base al valore di event.target.name.

Per esempio:

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

Link all'esempio: https://codesandbox.io/s/6l6v9p0qkr

Inizialmente, nessuno dei pulsanti di opzione è selezionato, quindi this.stateè un oggetto vuoto, ma ogni volta che il pulsante di opzione è selezionato this.stateottiene una nuova proprietà con il nome dell'ingresso e il suo valore. È quindi facile verificare se l'utente ha selezionato un pulsante di opzione come:

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

MODIFICARE:

Con la versione 16.7-alpha di React c'è una proposta per qualcosa chiamatohooks che ti permetterà di fare questo tipo di cose più facilmente:

Nell'esempio seguente ci sono due gruppi di pulsanti di opzione in un componente funzionale. Tuttavia, hanno input controllati:

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];
}

Esempio di lavoro: https://codesandbox.io/s/6l6v9p0qkr


20

Rendi il componente radio come componente stupido e passa oggetti di scena dal genitore.

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
è facile da testare in quanto il componente di dump è una funzione pura.
Khalid Azam,

7

Solo un'idea qui: quando si tratta di ingressi radio in React, di solito li rendo tutti in un modo diverso che è stato menzionato nelle risposte precedenti.

Se questo potrebbe aiutare chiunque abbia bisogno di eseguire il rendering di molti pulsanti di opzione:

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
Questo è fantastico Molto secco e rende le cose belle. Vorrei usare un oggetto per ogni opzione, ma è una questione di preferenza, immagino.
nbkhope,

@nbkhope se dovessi riscriverlo, userei anche l'oggetto! :)
Arnaud,

Controllare questa linea: checked={ this.state.gender === value }. I componenti funzionali non hanno this.
Abraham Hernandez il

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
Il tuo codice funziona ma dovresti anche spiegarlo un po '
Rahul Sharma,

NOTA : NON usare preventDefault nel gestore onChange perché impedisce l'impostazione controllata al componente DOM
AlexNikonov,

2

Fare clic su un pulsante di opzione dovrebbe attivare un evento che:

  1. chiama setState, se si desidera solo che la conoscenza della selezione sia locale o
  2. chiama un callback che è stato passato dall'alto self.props.selectionChanged(...)

Nel primo caso, la modifica è stato attiverà un nuovo rendering e puoi farlo
<td>chosen site name {this.state.chosenSiteName} </td>

nel secondo caso, l'origine del callback aggiornerà le cose per garantire che, lungo la linea, l'istanza di SearchResult avrà scelto SiteName e SetAddress impostato nei suoi oggetti di scena.


2

Sulla base di ChinKang detto per la sua risposta, ho un approccio più asciutto e in es6 per coloro che sono interessati:

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

tranne questo avrebbe un valore controllato predefinito.


1

Mi sono anche confuso in radio, implementazione checkbox. Ciò di cui abbiamo bisogno è ascoltare l'evento change della radio, quindi impostare lo stato. Ho fatto un piccolo esempio di selezione di genere.

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

Bootstrap ragazzi, lo facciamo in questo modo:


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>
        </>
    )
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.