Wie verwende ich Optionsfelder in ReactJS?

203

Ich bin neu bei ReactJS. Tut mir leid, wenn das nicht klingt. Ich habe eine Komponente, die mehrere Tabellenzeilen entsprechend den empfangenen Daten erstellt.

Jede Zelle in der Spalte verfügt über ein Optionsfeld. Daher kann der Benutzer eine site_nameund eine addressaus den vorhandenen Zeilen auswählen . Die Auswahl wird in der Fußzeile angezeigt. Und dort stecke ich fest.

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 könnte ich so etwas wie $("input[name=site_name]:checked").val()die Auswahl eines Radio-Kontrollkästchentyps abrufen und in die erste Fußzeilenzelle einfügen.

Aber es muss doch einen Reactjs-Weg geben, den ich total vermisse? Danke vielmals

Houman
quelle
3
inputElemente haben keinen Inhalt. Macht also <input>content</input>keinen Sinn und ist ungültig. Vielleicht möchten Sie <label><input />content</label>.
Oriol
1
Müssen Optionsfelder nicht dieselben Namen mit unterschiedlichen Werten haben, um zu funktionieren?
pgee70

Antworten:

209

Alle Änderungen am Rendering sollten über das stateoder props( React Doc ) geändert werden .

Also registriere ich hier das Ereignis der Eingabe und ändere dann das state, wodurch das Rendern ausgelöst wird, das in der Fußzeile angezeigt wird.

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

ChinKang
quelle
3
Das war sehr nützlich. Vielen Dank. Was ich nicht verstehe, ist das Stück }, this);direkt unter dem </tbody>. Was ist das und was macht es? Mir ist aufgefallen, ohne dass der Code abstürzt.
Houman
3
Dies thisist der Kontext, der an die mapFunktion übergeben wird . Es war die Bearbeitung von @FakeRainBrigand, guter Fang! Ohne es wird Ihre thisin der Karte Funktion auf die verweisen window, die keine Ahnung hat, worum es stategeht
ChinKang
8
Dieser thisTrick ist nicht erforderlich, wenn Sie anstelle einer regulären Funktion einen ES6-Pfeil verwenden. Beispiel: var resultRows = this.props.data.map((result) => { ... });Ich erwähne es nur, weil Reaktoren normalerweise bereits irgendeine Form der Transpilation (für JSX) verwenden, sodass ES6 normalerweise leicht zu erreichen ist.
Tom
1
Die Verwendung von zwei Funktionen zum Abrufen der Werte der Optionsfelder erscheint mehrdeutig und unnötig. Sie könnten vielleicht nur eine Funktion definierenonInputChange (e) {this.setState({ [e.target.name]: e.target.value }); }
xplorer1
108

Hier ist eine einfachste Möglichkeit, Optionsfelder in Reaktion js zu implementieren.

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>

Bearbeitet

Sie können die Pfeilfunktion anstelle der Bindung verwenden. Ersetzen Sie den obigen Code als

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

Für einen Standardwert verwenden defaultChecked, wie dieser

<input type="radio" value="MALE" defaultChecked name="gender"/> Male
Saahithyan Vigneswaran
quelle
6
Ich glaube .bind(this), dass jedes Mal eine neue Funktion geschaffen wird. Das heißt, wenn die Reaktion prüft, ob sich im virtuellen DOM etwas geändert hat, ist diese Komponente immer anders und muss immer wieder gerendert werden.
WoodenKitty
1
Die neue Funktion bei jedem Rendern wäre nur dann ein Problem, wenn diese Funktion als Requisiten an eine untergeordnete Komponente weitergegeben würde. In diesem Fall wird die untergeordnete Komponente, die die Requisiten empfängt, möglicherweise unnötig gerendert. Die übergeordnete Komponente wäre in Ordnung.
Mark McKelvy
5
Bei mir funktioniert dies nur einmal, wenn Sie auf jedes Radio mit demselben Namen klicken. Zum Beispiel habe ich zwei Radios, die die gleiche nameRequisite haben. Sie sind beide in ein Div eingewickelt, das den onChangein dieser Antwort beschriebenen Handler hat . Ich klicke auf das erste Radio, ein Ereignis wird ausgelöst. Ich klicke auf das zweite Radio, ein Ereignis wird ausgelöst. Ab dem dritten Mal wird jedoch kein Ereignis ausgelöst. Warum?
Squrler
4
@ Saahithyan Ich hatte das gleiche Namensattribut an alle Radios angehängt. Es stellte sich heraus, dass ich anstelle eines onChange-Handlers einen onClick-Handler an die Radioeingänge anschließen musste. Das hat funktioniert.
Squrler
3
Ich stimme @Squrler zu - bei onChange wird der Griff nur einmal für jedes der Optionsfelder ausgelöst, die unter dem div enthalten sind. Mit onClick funktioniert es mehrmals. Ich
bin
25

Basierend auf den Aussagen von React Docs :

Umgang mit mehreren Eingaben. Wenn Sie mehrere gesteuerte Eingabeelemente verarbeiten müssen, können Sie jedem Element ein Namensattribut hinzufügen und die Handlerfunktion basierend auf dem Wert von event.target.name auswählen lassen, was zu tun ist.

Beispielsweise:

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 zum Beispiel: https://codesandbox.io/s/6l6v9p0qkr

Zunächst ist keines der Optionsfelder ausgewählt, daher this.statehandelt es sich um ein leeres Objekt. Wenn jedoch das Optionsfeld ausgewählt wird, this.statewird eine neue Eigenschaft mit dem Namen der Eingabe und ihrem Wert abgerufen. Es ist dann einfacher zu überprüfen, ob der Benutzer ein Optionsfeld wie das folgende ausgewählt hat.

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

BEARBEITEN:

Mit Version 16.7-alpha von React gibt es einen Vorschlag für etwas namens, mit hooksdem Sie solche Dinge einfacher erledigen können:

Im folgenden Beispiel gibt es zwei Gruppen von Optionsfeldern in einer Funktionskomponente. Dennoch haben sie Eingänge gesteuert:

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

Arbeitsbeispiel: https://codesandbox.io/s/6l6v9p0qkr

Tomasz Mularczyk
quelle
20

Machen Sie die Funkkomponente zu einer dummen Komponente und geben Sie die Requisiten vom Elternteil weiter.

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;
Khalid Azam
quelle
2
Es ist einfach zu testen, da es sich bei der Dump-Komponente um eine reine Funktion handelt.
Khalid Azam
7

Nur eine Idee hier: Wenn es um Funkeingänge in React geht, rendere ich normalerweise alle auf eine andere Art und Weise, die in den vorherigen Antworten erwähnt wurde.

Wenn dies jemandem helfen könnte, der viele Optionsfelder rendern muss:

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>

Arnaud
quelle
1
Das ist toll. Sehr trocken und macht die Dinge schön. Ich würde für jede Option ein Objekt verwenden, aber es ist eine Frage der Präferenz, denke ich.
nbkhope
@nbkhope wenn ich es umschreiben müsste, würde ich stattdessen auch object verwenden! :)
Arnaud
Überprüfen Sie diese Zeile : checked={ this.state.gender === value }. Funktionskomponenten haben nicht this.
Abraham Hernandez
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;
ABHIJEET KHIRE
quelle
1
Ihr Code funktioniert, aber Sie sollten es auch ein wenig erklären
Rahul Sharma
HINWEIS : DONT Verwendung prevent in onChange Handler , weil es verhindert Einstellung überprüft , um DOM Komponente
AlexNikonov
2

Das Klicken auf ein Optionsfeld sollte ein Ereignis auslösen, das entweder:

  1. ruft setState auf, wenn das Auswahlwissen nur lokal sein soll, oder
  2. ruft einen Rückruf auf, der von oben übergeben wurde self.props.selectionChanged(...)

Im ersten Fall löst die Änderung des Status ein erneutes Rendern aus, und Sie können dies tun
<td>chosen site name {this.state.chosenSiteName} </td>

Im zweiten Fall aktualisiert die Quelle des Rückrufs die Dinge, um sicherzustellen, dass Ihre SearchResult-Instanz später in den Requisiten den Namen "Site-Name" und "Adresse ausgewählt" hat.

z5h
quelle
2

Um auf ChinKang aufzubauen, sagte er für seine Antwort, ich habe einen trockeneren Ansatz und in es6 für die Interessierten:

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

außer dass dieser einen standardmäßig aktivierten Wert haben würde.

Tony Tai Nguyen
quelle
1

Ich war auch verwirrt im Radio, Checkbox-Implementierung. Was wir brauchen, ist, das Änderungsereignis des Radios zu hören und dann den Status festzulegen. Ich habe ein kleines Beispiel für die Auswahl der Geschlechter gemacht.

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

rab
quelle
0

Bootstrap Jungs, wir machen das so:


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>
        </>
    )
}
GilbertS
quelle