Pobierz dane formularza w ReactJS

199

W mojej renderfunkcji mam prosty formularz , taki jak:

render : function() {
      return (
        <form>
          <input type="text" name="email" placeholder="Email" />
          <input type="password" name="password" placeholder="Password" />
          <button type="button" onClick={this.handleLogin}>Login</button>
        </form>
      );
    },
handleLogin: function() {
   //How to access email and password here ?
}

Co powinienem napisać, handleLogin: function() { ... }aby uzyskać dostęp Emaili Passwordpola?

myusuf
źródło
11
@ssorallen Co to za bzdury? Pytający może budować SPA i prawdopodobnie nie chce, aby formularz był przesyłany jak zwykły formularz HTML. Gdyby tego chcieli, zdefiniowaliby akcję i usunęli moduł obsługi zdarzeń.
developerbmw
6
Uwaga: powinieneś obsłużyć onSubmitformularz, a nie kliknięcie przycisku - w ten sposób obsłużysz również użytkownika wysyłającego formularz, naciskając klawisz enter.
developerbmw
10
<form>Z <button>lub <input>ze type=submitbędzie się składać, gdy użytkownik naciśnie klawisz Enter w jakikolwiek formularza użytkownika <input type=text>. Jeśli korzystasz onClickz jednego przycisku, użytkownik musi kliknąć przycisk lub ustawić go i nacisnąć Enter / Spacja. Użycie onSubmitspowoduje włączenie obu przypadków użycia. Kiedy formularze nie obsługują Enter do przesyłania, mogą czuć się złamane.
Ross Allen

Odpowiedzi:

167

Użyj changezdarzeń na wejściach, aby zaktualizować stan komponentu i uzyskać do niego dostęp w handleLogin:

handleEmailChange: function(e) {
   this.setState({email: e.target.value});
},
handlePasswordChange: function(e) {
   this.setState({password: e.target.value});
},
render : function() {
      return (
        <form>
          <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} />
          <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
          <button type="button" onClick={this.handleLogin}>Login</button>
        </form>);
},
handleLogin: function() {
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
}

Skrzypce robocze .

Przeczytaj także dokumenty, jest cała sekcja poświęcona obsłudze formularzy : Formularze

Wcześniej można było również użyć dwukierunkowej miksera pomocnika wiązania danych React, aby osiągnąć to samo, ale teraz jest on przestarzały na rzecz ustawiania wartości i zmiany procedury obsługi (jak wyżej):

var ExampleForm = React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function() {
    return {email: '', password: ''};
  },
  handleLogin: function() {
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
  },
  render: function() {
    return (
      <form>
        <input type="text" valueLink={this.linkState('email')} />
        <input type="password" valueLink={this.linkState('password')} />
        <button type="button" onClick={this.handleLogin}>Login</button>
      </form>
    );
  }
});

Dokumentacja jest tutaj: dwukierunkowe łączenie pomocników .

jbaiter
źródło
3
Aby poprawnie naśladować funkcjonalność valueLink, w pierwszym przykładzie należy ustawić valueelementy wejściowe. Bez tego wartości są „niekontrolowane” w kategoriach React. <input ... value={this.state.password}>.
Ross Allen
10
możesz również użyć formularza onSubmit zamiast formularza onClick za pomocą przycisku
sai
58
Po co używać stanu dla każdego elementu formularza? Czy ktoś jeszcze uważa, że ​​to zły wzór?
eveevans
6
Wygląda na to, że valueLink jest przestarzałe
Matt Broekhuis
3
Czy to nie przechowuje hasła przez cały czas w postaci zwykłego tekstu? Nie wydaje się to właściwe dla pola hasła.
NewbiZ
166

Można to zrobić na kilka sposobów:

1) Uzyskaj wartości z tablicy elementów formularza według indeksu

handleSubmit = (event) => {
  event.preventDefault();
  console.log(event.target[0].value)
}

2) Używanie atrybutu nazwy w HTML

handleSubmit = (event) => {
  event.preventDefault();
  console.log(event.target.elements.username.value) // from elements property
  console.log(event.target.username.value)          // or directly
}

<input type="text" name="username"/>

3) Korzystanie z referencji

handleSubmit = (event) => {
  console.log(this.inputNode.value)
}

<input type="text" name="username" ref={node => (this.inputNode = node)}/>

Pełny przykład

class NameForm extends React.Component {
  handleSubmit = (event) => {
    event.preventDefault()
    console.log(event.target[0].value)
    console.log(event.target.elements.username.value)
    console.log(event.target.username.value)
    console.log(this.inputNode.value)
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            name="username"
            ref={node => (this.inputNode = node)}
          />
        </label>
        <button type="submit">Submit</button>
      </form>
    )
  }
}
Aliaksandr Sushkevich
źródło
1
To fantastyczna odpowiedź. Dziękujemy za podanie wielu sposobów, aby to zrobić.
Beau Smith
Opcja 2 nie działa dla mnie. Nie ma właściwości „elementy” ani „nazwa użytkownika”, mimo że moje dane wejściowe to „nazwa użytkownika”
Madacol,
@Madacol może się tak zdarzyć, jeśli masz kilka danych wejściowych o tej samej nazwie
Aliaksandr Sushkevich
45

Alternatywnym podejściem jest użycie refatrybutu i odwołanie się do wartości this.refs. Oto prosty przykład:

render: function() {
    return (<form onSubmit={this.submitForm}>
        <input ref="theInput" />
    </form>);
},
submitForm: function(e) {
    e.preventDefault();
    alert(React.findDOMNode(this.refs.theInput).value);
}

Więcej informacji można znaleźć w dokumentach React: https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute

Z wielu powodów opisanych w Jak używać przycisków opcji w React? takie podejście nie zawsze jest najlepsze, ale w niektórych prostych przypadkach stanowi użyteczną alternatywę.

Jamund Ferguson
źródło
1
Czy to rozwiązanie jest naprawdę lepsze i nie było dostępne w czasie pytań, czy też jest „brzydkie”?
Wagner Leonardi
4
właściwie nie potrzebujesz React.findDOMNode this.refs.theInput jest już węzłem HTML
Fareed Alnamrouti
23

Łatwy sposób radzenia sobie z referencjami:

class UserInfo extends React.Component {

  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    e.preventDefault();
    
    const formData = {};
    for (const field in this.refs) {
      formData[field] = this.refs[field].value;
    }
    console.log('-->', formData);
  }

  render() {
    return (
        <div>
          <form onSubmit={this.handleSubmit}>
            <input ref="phone" className="phone" type='tel' name="phone"/>
            <input ref="email" className="email" type='tel' name="email"/>
            <input type="submit" value="Submit"/>
          </form>
        </div>
    );
  }
}

export default UserInfo;

E. Fortes
źródło
2
Ta metoda kiedyś będzie przestarzała. Odniesień należy używać tylko z wywołaniami zwrotnymi, a nie ciągami znaków. Aby uzyskać więcej informacji: facebook.github.io/react/docs/refs-and-the-dom.html
David Labbe
Chłodny! :) Lubię używać Object.keys()następującego dla map():Object.keys(this.refs).map(field => formData[field] = this.refs[field].value)
Francis Rodrigues
Tak, referencje ciągu są przestarzałe. Lepszym sposobem na zrobienie tego teraz jest użycie wywołania zwrotnego onChange. Jeśli nadal chcesz używać referencji, możesz użyć tej synctax:<input type="text" ref={(input) => { this.textInput = input; }} />
E. Fortes
I @ E.Fortes, czy możesz wyjaśnić metodę wywołania zwrotnego onChange? Dziękuję bardzo, jeśli chcesz. Proszę otaguj mnie, abym został poinformowany o twojej odpowiedzi.
Simona Adriani,
prostym sposobem byłoby (przepraszam, że formatator kodu nie działa): klasa NameForm rozszerza React.Component {constructor (props) {super (props); this.state = {wartość: ''}; this.handleChange = this.handleChange.bind (this); } handleChange (event) {this.setState ({wartość: event.target.value}); } render () {return (<form> <label> Nazwa: <input type = "text" value = {this.state.value} onChange = {this.handleChange} /> </label> </form>); }}
E. Fortes
22

Uzupełnienie odpowiedzi Michaela Schocka:

class MyForm extends React.Component {
  constructor() {
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    event.preventDefault();
    const data = new FormData(event.target);

    console.log(data.get('email')); // reference by form input's `name` tag

    fetch('/api/form-submit-url', {
      method: 'POST',
      body: data,
    });
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label htmlFor="username">Enter username</label>
        <input id="username" name="username" type="text" />

        <label htmlFor="email">Enter your email</label>
        <input id="email" name="email" type="email" />

        <label htmlFor="birthdate">Enter your birth date</label>
        <input id="birthdate" name="birthdate" type="text" />

        <button>Send data!</button>
      </form>
    );
  }
}

Zobacz ten średni artykuł: Jak obsługiwać formularze za pomocą Just React

Ta metoda pobiera dane formularza tylko po naciśnięciu przycisku Prześlij. Znacznie czystsze IMO!

hoohoo-b
źródło
Idealna odpowiedź. 👌
Michał,
16

Możesz przełączyć onClickmoduł obsługi zdarzeń na przycisku do onSubmitmodułu obsługi w formularzu:

render : function() {
      return (
        <form onSubmit={this.handleLogin}>
          <input type="text" name="email" placeholder="Email" />
          <input type="password" name="password" placeholder="Password" />
          <button type="submit">Login</button>
        </form>
      );
    },

Następnie możesz użyć FormDataparsowania formularza (i zbudować obiekt JSON z jego wpisów, jeśli chcesz).

handleLogin: function(e) {
   const formData = new FormData(e.target)
   const user = {}

   e.preventDefault()

   for (let entry of formData.entries()) {
       user[entry[0]] = entry[1]
   }

   // Do what you will with the user object here
}
Michael Schock
źródło
Uruchamianie tego plus „console.log (użytkownik);” daje obiekt bez wartości użytkowej! Jakieś opinie?
M o
@MahdiRafatjah ¯ \ _ (ツ) _ / ¯ - działa w tym skrzypcach: jsfiddle.net/mschock/exvko2Lf
Michael Schock
mój przyjaciel polecił
M w
1
fajnie, to wydaje się znacznie czystsze =)
Michael Schock
13

Sugerowałbym następujące podejście:

import {Autobind} from 'es-decorators';

export class Form extends Component {

    @Autobind
    handleChange(e) {
        this.setState({[e.target.name]: e.target.value});
    }

    @Autobind
    add(e) {
        e.preventDefault();
        this.collection.add(this.state);
        this.refs.form.reset();
    }

    shouldComponentUpdate() {
        return false;
    }

    render() {
        return (
            <form onSubmit={this.add} ref="form">
                <input type="text" name="desination" onChange={this.handleChange}/>
                <input type="date" name="startDate" onChange={this.handleChange}/>
                <input type="date" name="endDate" onChange={this.handleChange}/>
                <textarea name="description" onChange={this.handleChange}/>
                <button type="submit">Add</button>
            </form>
        )
    }

}
James Akwuh
źródło
Jeśli nie wyrenderujesz ponownie komponentu, jak możesz ustawić wartość każdego elementu zgodnie z bieżącym stanem? np. „wartość = {this.state. destination}”. Ponadto nie możesz uruchomić sprawdzania poprawności formularza, jeśli go nie wyślesz ponownie
Avishay28
13

Jeśli wszystkie twoje dane wejściowe / tekstowe mają nazwę, możesz odfiltrować wszystkie z event.target:

onSubmit(event){
  const fields = Array.prototype.slice.call(event.target)
      .filter(el => el.name)
      .reduce((form, el) => ({
        ...form,
        [el.name]: el.value,
      }), {})
}

Całkowicie niekontrolowana forma 😊 bez metod onChange, wartość, defaultValue ...

Aral Roca
źródło
12

Dla tych, którzy nie chcą używać ref i resetować stanu ze OnChangezdarzeniem, możesz po prostu użyć prostego uchwytu OnSubmit i zapętlić FormDataobiekt. W tym przykładzie użyto React Hooks:

const LoginPage = () =>{
    const handleSubmit = (event) => {
        const formData = new FormData(event.target);
        event.preventDefault();
        for (var [key, value] of formData.entries()) {
            console.log(key, value);
        }
    }

    return (
        <div>
        <form onSubmit={
        handleSubmit
        }

        >
        <input type="text" name="username" placeholder="Email" />
        <input type="password" name="password"
        placeholder="Password" />
        <button type="submit">Login</button>
        </form>
        </div>)
        }
CloudWave
źródło
Świetna odpowiedź, ale nitpick mógłby usunąć var ​​inaczej idealne rozwiązanie!
Louis345
5

Można to również wykorzystać.

handleChange: function(state,e) {
  this.setState({[state]: e.target.value});
},
render : function() {
  return (
    <form>
      <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleChange.bind(this, 'email')} />
      <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handleChange.bind(this, 'password')}/>
      <button type="button" onClick={this.handleLogin}>Login</button>
    </form>
  );
},
handleLogin: function() {
  console.log("EMail: ", this.state.email);
  console.log("Password: ", this.state.password);
}
Jurij Kosygin
źródło
4
Podaj wyjaśnienie, dlaczego ta odpowiedź jest właściwą drogą.
Tim Hutchison
1
Używam tylko jednej metody zmiany formy tekstowej
Yurii Kosygin
Hasło można zobaczyć w reagujących narzędziach programistycznych, trochę problem z bezpieczeństwem?
Neil
5

Podaj swoje dane referencyjne w ten sposób

<input type="text" name="email" placeholder="Email" ref="email" />
<input type="password" name="password" placeholder="Password" ref="password" />

wtedy możesz uzyskać do niego dostęp w swoim uchwycie Zaloguj się jak soo

handleLogin: function(e) {
   e.preventDefault();
    console.log(this.refs.email.value)
    console.log(this.refs.password.value)
}
Imran Rafique
źródło
5

Bardziej wyraźny przykład z niszczeniem es6

class Form extends Component {
    constructor(props) {
        super(props);
        this.state = {
            login: null,
            password: null,
            email: null
        }
    }

    onChange(e) {
        this.setState({
            [e.target.name]: e.target.value
        })
    }

    onSubmit(e) {
        e.preventDefault();
        let login = this.state.login;
        let password = this.state.password;
        // etc
    }

    render() {
        return (
            <form onSubmit={this.onSubmit.bind(this)}>
                <input type="text" name="login" onChange={this.onChange.bind(this)} />
                <input type="password" name="password" onChange={this.onChange.bind(this)} />
                <input type="email" name="email" onChange={this.onChange.bind(this)} />
                <button type="submit">Sign Up</button>
            </form>
        );
    }
}
Sergio Ivanuzzo
źródło
4

W wielu wydarzeniach w javascript mamy event który zawiera to, co się wydarzyło i jakie są wartości itp.

Tego właśnie używamy z formularzami w ReactJs ...

Więc w kodzie ustawiłeś stan na nową wartość ... coś takiego:

class UserInfo extends React.Component {

  constructor(props) {
    super(props);
    this.handleLogin = this.handleLogin.bind(this);
  }

  handleLogin(e) {
    e.preventDefault();
    for (const field in this.refs) {
      this.setState({this.refs[field]: this.refs[field].value});
    }
  }

  render() {
    return (
        <div>
          <form onSubmit={this.handleLogin}>
            <input ref="email" type="text" name="email" placeholder="Email" />
            <input ref="password" type="password" name="password" placeholder="Password" />
            <button type="button">Login</button>
          </form>
        </div>
    );
  }
}

export default UserInfo;

Jest to również przykład formularza w React v.16, podobnie jak odniesienie do formularza, który utworzysz w przyszłości:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
Alireza
źródło
4

Używam w ten sposób, używając stanu React Component:

<input type="text" name='value' value={this.state.value} onChange={(e) => this.handleChange(e)} />

handleChange(e){
   this.setState({[e.target.name]: e.target.value})
}`
Adnan Boota
źródło
3
 onChange(event){
     console.log(event.target.value);
  }
  handleSubmit(event){ 
    event.preventDefault();
    const formData = {};
      for (const data in this.refs) {
        formData[data] = this.refs[data].value;
      }
    console.log(formData);
  }



 <form onSubmit={this.handleSubmit.bind(this)}>
  <input type="text" ref="username" onChange={this.onChange} className="form-control"/>
  <input type="text" ref="password" onChange={this.onChange} className="form-control"/>
  <button type="submit" className="btn-danger btn-sm">Search</button>
 </form>

Załączony obraz wyjściowy

Milan Panigrahi
źródło
Podaj także wyjaśnienie.
BlackBeard
2
Spróbuję to wyjaśnić, co uważam za genialne. W funkcji handleSubmit () budujesz obiekt (formData), w którym klucz jest atrybutem „ref” każdego wejścia w formularzu (instrukcja „formData [data]”), a wartość jest wartością wejścia z tym atrybutem „ref” (instrukcja „this.refs [data] .value”). Z 'formData [data] = this.refs [data] .value' budujesz ten obiekt. Mówisz dosłownie: formData ['nazwa użytkownika'] = (wartość wejściowa nazwy użytkownika) i formData ['hasło'] = (wartość wejściowa hasła) Wyjście będzie: {użytkownik: 'blablabla', hasło: 'xxx '}
Simona Adriani,
Dziękuję @SimonaAdriani za wyjaśnienie.
Milan Panigrahi,
2

Może to pomóc użytkownikom Meteor (v1.3):

render: function() {
    return (
        <form onSubmit={this.submitForm.bind(this)}>
            <input type="text" ref="email" placeholder="Email" />
            <input type="password" ref="password" placeholder="Password" />
            <button type="submit">Login</button>
        </form>
    );
},
submitForm: function(e) {
    e.preventDefault();
    console.log( this.refs.email.value );
    console.log( this.refs.password.value );
}
Joe L.
źródło
1
this.submitForm.bind (this) powinno być po prostu: this.submitForm
rekarnar
Błąd: komponenty funkcji bezstanowej nie mogą mieć referencji.
Holms
Czy korzystasz z Meteora (v1.3)?
Joe L.,
1

Aby poprawić wrażenia użytkownika; gdy użytkownik kliknie przycisk Prześlij, możesz spróbować uzyskać formularz, aby najpierw wyświetlić wiadomość wysyłającą. Gdy otrzymamy odpowiedź z serwera, może on odpowiednio zaktualizować wiadomość. Osiągamy to w React poprzez łączenie stanów. Zobacz codepen lub fragmenty poniżej:

Następująca metoda wprowadza pierwszą zmianę stanu:

handleSubmit(e) {
    e.preventDefault();
    this.setState({ message: 'Sending...' }, this.sendFormData);
}

Gdy tylko React wyświetli powyższy komunikat Wysyłanie na ekranie, wywoła metodę, która wyśle ​​dane formularza na serwer: this.sendFormData (). Dla uproszczenia dodałem setTimeout, aby to naśladować.

sendFormData() {
  var formData = {
      Title: this.refs.Title.value,
      Author: this.refs.Author.value,
      Genre: this.refs.Genre.value,
      YearReleased: this.refs.YearReleased.value};
  setTimeout(() => { 
    console.log(formData);
    this.setState({ message: 'data sent!' });
  }, 3000);
}

W React metoda this.setState () renderuje komponent z nowymi właściwościami. Możesz więc dodać także logikę do metody render () komponentu formularza, który będzie zachowywał się inaczej w zależności od rodzaju odpowiedzi otrzymanej z serwera. Na przykład:

render() {
  if (this.state.responseType) {
      var classString = 'alert alert-' + this.state.type;
      var status = <div id="status" className={classString} ref="status">
                     {this.state.message}
                   </div>;
  }
return ( ...

codepen

Homam Bahrani
źródło
1

Jeśli masz wiele wystąpień nazwy elementu, musisz użyć forEach ().

HTML

  <input type="checkbox" name="delete" id="flizzit" />
  <input type="checkbox" name="delete" id="floo" />
  <input type="checkbox" name="delete" id="flum" />
  <input type="submit" value="Save"  onClick={evt => saveAction(evt)}></input>

js

const submitAction = (evt) => {
  evt.preventDefault();
  const dels = evt.target.parentElement.delete;
  const deleted = [];
  dels.forEach((d) => { if (d.checked) deleted.push(d.id); });
  window.alert(deleted.length);
};

Zauważ, że dels w tym przypadku to RadioNodeList, a nie tablica i nie jest iterowalna. ForEach () jest wbudowaną metodą klasy list. W tym miejscu nie będzie można używać mapy () ani zmniejszania ().

Jeff Lowery
źródło
1

AKTUALIZACJA: Możesz teraz używać Formik zewnętrznego pakietu React, który sprawia, że ​​obsługa formularzy jest tak prosta!

Oto link, aby zacząć

https://jaredpalmer.com/formik

Ubaid Parvaiiz
źródło