Получить данные формы в ReactJS

200

У меня есть простая форма в моей renderфункции, например так:

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

Что я должен написать в моем handleLogin: function() { ... }доступе Emailи Passwordполях?

myusuf
источник
6
Примечание: вы должны обрабатывать onSubmitформу, а не нажатие кнопки - таким образом вы также будете обрабатывать пользователя, отправляющего форму, нажав клавишу ввода.
developerbmw
11
<form>С <button>или <input>с type=submitполучите представлен , когда пользователь нажимает Enter в любой из форм - х <input type=text>. Если вы полагаетесь на onClickкнопку, пользователь должен щелкнуть по кнопке или сфокусировать ее и нажать Enter / пробел. Использование onSubmitвключит оба варианта использования. Когда формы не поддерживают Enter для отправки, они могут чувствовать себя разбитыми.
Росс Аллен

Ответы:

167

Используйте changeсобытия на входах, чтобы обновить состояние компонента и получить к нему доступ 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);
}

Рабочая скрипка .

Кроме того, прочитайте документы, есть целый раздел, посвященный обработке форм : Формы

Раньше вы могли также использовать двусторонний вспомогательный миксин привязки данных React для достижения того же результата, но теперь он устарел в пользу установки значения и изменения обработчика (как указано выше):

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

Документация здесь: Помощники двусторонней привязки .

jbaiter
источник
3
Чтобы правильно имитировать функциональность valueLink, ваш первый пример должен установить valueэлементы ввода. Без этого значения «неуправляемы» в терминах React. <input ... value={this.state.password}>,
Росс Аллен
10
вы также можете использовать onSubmit с формой вместо onClick кнопкой
sai
60
Зачем использовать состояние для каждого элемента формы? Кто-нибудь еще думает, что это плохая картина?
Евееванс
6
Похоже, ValueLink устарела
Мэтт Брукхёйс
3
Разве это не хранит пароль открытым текстом на стороне клиента все время? Это не совсем подходит для поля пароля.
NewbiZ
166

Есть несколько способов сделать это:

1) Получить значения из массива элементов формы по индексу

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

2) Использование атрибута имени в 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) Использование ссылок

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

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

Полный пример

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>
    )
  }
}
Александр Сушкевич
источник
1
Это фантастический ответ. Спасибо за перечисление нескольких способов сделать это.
Бо Смит
Вариант 2 не работает для меня. Здесь нет ни свойств «elements», ни «username», хотя мой входной
файл
@Madacol это может произойти, если у вас есть несколько входов с тем же именем
Александр Сушкевич
45

Альтернативный подход - использовать refатрибут и ссылаться на значения this.refs. Вот простой пример:

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

Дополнительную информацию можно найти в документации React: https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute.

По многим причинам, описанным в разделе Как использовать переключатели в React? этот подход не всегда лучший, но он представляет полезную альтернативу в некоторых простых случаях.

Джамунд Фергюсон
источник
1
Действительно ли это решение лучше и не было доступно во время вопроса, или это «уродливый» способ?
Вагнер Леонарди
4
на самом деле вам не нужен React.findDOMNode this.refs.theInput уже html-узел
Фарид Алнамрути
23

Простой способ справиться с реферами:

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;

Э. Фортес
источник
2
Этот метод когда-нибудь в будущем станет устаревшим. Ссылки должны использоваться только с обратными вызовами, а не со строками. Для получения дополнительной информации: facebook.github.io/react/docs/refs-and-the-dom.html
Дэвид
Прохладно! :) Я хотел бы использовать Object.keys()для следования, map()как это:Object.keys(this.refs).map(field => formData[field] = this.refs[field].value)
Фрэнсис Родригес
Да, ссылки на строки устарели. Лучший способ сделать это прямо сейчас - использовать обратный вызов onChange. Если вы все еще хотите использовать ссылки, вы можете использовать этот synctax:<input type="text" ref={(input) => { this.textInput = input; }} />
E. Fortes
I @ E.Fortes, не могли бы вы объяснить метод обратного вызова onChange? Большое спасибо, если хотите. Пожалуйста, отметьте меня, чтобы я был проинформирован о вашем ответе.
Симона Адриани
простой способ (извините, кодировщик кода не работает): класс NameForm extends React.Component {constructor (props) {super (props); this.state = {значение: ''}; this.handleChange = this.handleChange.bind (this); } handleChange (event) {this.setState ({value: event.target.value}); } render () {return (<form> <label> Имя: <input type = "text" value = {this.state.value} onChange = {this.handleChange} /> </ label> </ form>); }}
Э. Фортес
23

Добавляем к ответу Майкла Шока:

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

Посмотрите эту среднюю статью: Как обрабатывать формы с помощью Just React

Этот метод получает данные формы только при нажатии кнопки «Отправить». Гораздо чище ИМО!

hoohoo-б
источник
Идеальный ответ. Mich
Михал
16

Вы можете переключить onClickобработчик события на кнопке на onSubmitобработчик в форме:

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

Затем вы можете использовать FormDataдля анализа формы (и, если хотите, построить объект JSON из его записей).

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
}
Майкл Шок
источник
Запуск этого плюса 'console.log (user);' дает объект без полезной ценности! Есть мнение?
М
@MahdiRafatjah ¯ \ _ (ツ) _ / ¯ - это работает в этой скрипке: jsfiddle.net/mschock/exvko2Lf
Майкл Шок
мой друг отослал
M
1
хорошо, что кажется намного чище =)
Майкл Шок
13

Я бы предложил следующий подход:

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

}
Джеймс Аквух
источник
Если вы не переопределяете компонент, как вы можете установить значение каждого элемента в соответствии с текущим состоянием? например, "value = {this.state. destination}". Кроме того, вы не можете запускать проверки реагирования в форме, если вы не рендеринг ее
Avishay28
13

Если все ваши входы / textarea имеют имя, вы можете отфильтровать все из event.target:

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

Полностью неконтролируемая форма 😊 без методов onChange, value, defaultValue ...

Араль Рока
источник
12

Для тех, кто не хочет использовать ref и сбрасывать состояние с OnChangeсобытием, вы можете просто использовать простой дескриптор OnSubmit и проходить через FormDataобъект. Этот пример использует 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
источник
Отличный ответ, но вы можете убрать вар, иначе идеальное решение!
Louis345
5

Кроме того, это тоже можно использовать.

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);
}
Юрий Косыгин
источник
4
Пожалуйста, включите объяснение, почему этот ответ правильный путь.
Тим Хатчисон
1
Я использую только один метод для изменения формы текста
Юрий Косыгин,
Пароль можно увидеть в инструментах реагирования, немного проблем с безопасностью?
Нил
5

Дайте ваши ссылки, как это

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

тогда вы можете получить к нему доступ в своем дескрипторе, как Су

handleLogin: function(e) {
   e.preventDefault();
    console.log(this.refs.email.value)
    console.log(this.refs.password.value)
}
Имран Рафике
источник
5

Более наглядный пример с разрушением 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>
        );
    }
}
Серхио Ивануццо
источник
4

Если вы используете Redux в своем проекте, вы можете рассмотреть возможность использования этого компонента более высокого порядка https://github.com/erikras/redux-form .

ivks
источник
4

Во многих событиях в javascript у нас eventесть объекты, которые дают объект, включая то, что произошло, и каковы значения и т. Д.

Это то, что мы используем с формами в ReactJs ...

Итак, в вашем коде вы устанавливаете состояние на новое значение ... что-то вроде этого:

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;

Также это пример формы в React v.16, просто как ссылка на форму, которую вы создадите в будущем:

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>
    );
  }
}
Алиреза
источник
4

Я использую так, используя состояние 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})
}`
Аднан Бута
источник
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>

Выходное изображение прилагается здесь

Милан Паниграхи
источник
Пожалуйста, предоставьте объяснение.
Черная Борода
2
Я постараюсь объяснить это, что я нашел блестящим. В функции handleSubmit () вы создаете объект (formData), в котором ключ является атрибутом 'ref' каждого ввода в форме (оператор 'formData [data]'), а значение является значением ввода с этим атрибутом ref (оператор this.refs [data] .value). С помощью 'formData [data] = this.refs [data] .value' вы создаете этот объект. Вы говорите буквально: formData ['username'] = (значение ввода имени пользователя) и formData ['password'] = (значение ввода пароля) Вывод будет: {user: 'blablabla', password: 'xxx '}
Симона Адриани
Спасибо @SimonaAdriani за ваше объяснение.
Милан Паниграхи
2

Это может помочь пользователям 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 );
}
Джо Л.
источник
1
this.submitForm.bind (this) должен быть просто: this.submitForm
rekarnar
Ошибка: компоненты функции без сохранения состояния не могут иметь ссылок.
Holms
Используете ли вы Метеор (v1.3)?
Джо Л.
1

Улучшить пользовательский опыт; когда пользователь нажимает на кнопку отправки, вы можете попытаться получить форму, чтобы сначала показать отправляющее сообщение. Получив ответ от сервера, он может соответствующим образом обновить сообщение. Мы достигаем этого в React путем объединения статусов. Смотрите кодовый блок или фрагменты ниже:

Следующий метод выполняет первое изменение состояния:

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

Как только React отобразит вышеприведенное сообщение об отправке на экране, он вызовет метод, который отправит данные формы на сервер: this.sendFormData (). Для простоты я добавил setTimeout, чтобы имитировать это.

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

В React метод this.setState () отображает компонент с новыми свойствами. Таким образом, вы также можете добавить некоторую логику в метод render () компонента формы, который будет вести себя по-разному в зависимости от типа ответа, который мы получаем от сервера. Например:

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

Хомам Бахрани
источник
1

Если у вас есть несколько вхождений имени элемента, вы должны использовать 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);
};

Обратите внимание, что dels в этом случае является RadioNodeList, а не массивом, и не является Iterable. ForEach () является встроенным методом класса списка. Вы не сможете использовать карту () или уменьшить () здесь.

Джефф Лоури
источник