У меня есть следующий компонент React:
export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
var title = this.title;
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};
Консоль дает мне undefined
- любые идеи, что не так с этим кодом?
Здесь есть три ответа, в зависимости от версии React, с которой вы (вынуждены) работать (с), и от того, хотите ли вы использовать хуки.
Делая вещи правильно, согласно документации React и учебникам. Вы пишете пользовательский интерфейс, основанный на двух вещах:
То, что вы не делаете - это генерируете DOM-узел элемента ввода и затем вводите его. Вы генерируете пользовательский интерфейс, который должен отображать текстовую строку, которую можно манипулировать, а манипуляции изменяют состояние компонента, что может вызвать повторное отображение. Государство всегда является последней инстанцией, а не DOM. DOM - это запоздалая мысль, это просто конкретная среда пользовательского интерфейса, которую вы используете.
Итак, для правильной работы у вашего компонента есть значение состояния, которое отображается через поле ввода, и мы можем обновить его, заставив этот элемент пользовательского интерфейса отправлять события изменения обратно в компонент:
var Component = React.createClass({
getInitialState: function() {
return {
inputValue: ''
};
},
render: function() {
return (
//...
<input value={this.state.inputValue} onChange={this.updateInputValue}/>
//...
);
},
updateInputValue: function(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
Вы вводите элемент input, с вашим элементом input пока ничего не происходит, событие было перехвачено и немедленно updateInputValue
, React вместо этого запускает функцию updateInputValue
для события. Эта функция запрашивает у React обновить состояние компонента, чтобы оно имело правильное значение, и тогда React может затем повторно представить ваш пользовательский интерфейс с новым обновлением, и только тогда пользовательский интерфейс покажет, что вы ввели букву. И все это происходит за считанные миллисекунды, так что похоже, что вы набрали что-то нормально, но это совсем не то, что произошло.
приложение на основе комментариев
Входные данные пользовательского интерфейса представляют значения состояния (рассмотрим, что происходит, если пользователь закрывает свою вкладку на полпути, и вкладка восстанавливается. Должны ли быть восстановлены все эти значения, которые они заполнили? Если да, то это состояние). Это может заставить вас чувствовать, что для большой формы нужны десятки или даже сотни форм ввода, но React - это моделирование вашего пользовательского интерфейса в удобной для обслуживания форме: у вас нет 100 независимых полей ввода, у вас есть группы связанных входов, поэтому вы фиксируете каждую из них. сгруппируйте в компонент, а затем создайте свою "основную" форму как набор групп.
MyForm:
render:
<PersonalData/>
<AppPreferences/>
<ThirdParty/>
...
Это также намного легче поддерживать, чем гигантский компонент с одной формой. Разделите группы на Компоненты с поддержкой состояния, где каждый компонент отвечает только за отслеживание нескольких полей ввода одновременно.
Вы также можете почувствовать себя "хлопотно" по написанию всего этого кода, но это ложная экономия: разработчики, которые не являются вами, включая вас самих, на самом деле очень выигрывают от того, что все эти входные данные явно подключены, потому что это значительно облегчает отслеживание путей кода. Тем не менее, вы всегда можете оптимизировать. Например, вы можете написать компоновщик состояния
MyComponent = React.createClass({
getInitialState() {
return {
firstName: this.props.firstName || "",
lastName: this.props.lastName || ""
...: ...
...
}
},
componentWillMount() {
Object.keys(this.state).forEach(n => {
let fn = n + 'Changed';
this[fn] = evt => {
let update = {};
update[n] = evt.target.value;
this.setState(update);
});
});
},
render: function() {
return Object.keys(this.state).map(n => {
<input
key={n}
type="text"
value={this.state[n]}
onChange={this[n + 'Changed']}/>
});
}
});
Конечно, есть улучшенные версии этого, поэтому зайдите на https://npmjs.com и найдите решение для связи с состоянием React, которое вам больше нравится. Open Source - это в основном поиск того, что уже сделали другие, и использование этого вместо того, чтобы писать все с нуля.
Начиная с React 16 (и программного запуска с 15.5) вызов createClass
больше не поддерживается, и необходимо использовать синтаксис класса. Это меняет две вещи: очевидный синтаксис класса, но также и привязку this
контекста, которую createClass
может делать "бесплатно", поэтому, чтобы гарантировать, что все по-прежнему работает, убедитесь, что вы используете нотацию "жирная стрелка" для this
контекста, сохраняя анонимные функции в onWhatever
обработчики, такие как onChange
мы используем в коде здесь:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
};
}
render() {
return (
//...
<input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
//...
);
},
updateInputValue(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
Возможно, вы также видели, как люди использовали bind
в своем конструкторе для всех своих функций обработки событий, например:
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
...
}
render() {
return (
...
<element onclick={this.handler}/>
...
);
}
Не делай этого.
Практически каждый раз, когда вы используете bind
, применяется пресловутое выражение "вы делаете это неправильно". Ваш класс уже определяет прототип, используйте обычную пересылку событий вместо дублирования всех ваших вызовов функций в конструкторе. Теперь вы увеличили свою поверхность ошибки и усложнили отслеживание ошибок, потому что проблема может быть в вашем конструкторе, а не в том месте, где вы вызываете свой код. В дополнение к бремени обслуживания на других, с которыми вы (имеете или выбираете) работать.
Да, я знаю, что реагирующие документы говорят это хорошо. Это не так, не делай этого.
По состоянию на React 16.8 функцию компоненты (то есть буквально только функция, которая Thats некоторого props
в качестве аргумента можно использовать, как будто это экземпляр класса компонента, никогда не писать класс) также может быть предоставлено государством, посредством использования крючков.
Если вам не нужен полный код класса, и подойдет одна функция экземпляра, то теперь вы можете использовать хук useState
чтобы получить единственную переменную состояния и ее функцию обновления, которая работает примерно так же, как и в приведенных выше примерах, за исключением без setState
функции setState
:
import { useState } from 'react';
function myFunctionalComponentFunction() {
const [input, setInput] = useState(''); // '' is the initial state value
return (
<div>
<label>Please specify:</label>
<input value={input} onInput={e => setInput(e.target.value)/>
</div>
);
}
Ранее неофициальным аргументом между классами и компонентами функций было "компоненты функций не имеют состояния", поэтому мы не можем больше скрывать это: различие между компонентами функций и компонентами классов можно найти на нескольких страницах очень хорошо. написанная документация о реагировании (нет кратких пояснений, которые удобно интерпретировать для вас!), которые вы должны прочитать, чтобы знать, что вы делаете, и, таким образом, знать, выбрали ли вы лучшее (что бы это ни значило для вас) решение для программирования себя из вашей проблемы.
Удалось получить значение поля ввода, выполнив что-то вроде этого:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
username : ''
}
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
updateInput(event){
this.setState({username : event.target.value})
}
handleSubmit(){
console.log('Your input value is: ' + this.state.username)
//Send state to the server code
}
render(){
return (
<div>
<input type="text" onChange={this.updateInput}></input>
<input type="submit" onClick={this.handleSubmit} ></input>
</div>
);
}
}
//output
//Your input value is: x
В реакции 16 я использую
<Input id="number"
type="time"
onChange={(evt) => { console.log(evt.target.value); }} />
Мне удалось это сделать, привязав "this" к функции updateInputValue (evt) с
this.updateInputValue = this.updateInputValue.bind(this);
Однако входное value = {this.state.inputValue}... оказалась не очень хорошей идеей.
Здесь полный код в babel ES6:
class InputField extends React.Component{
constructor(props){
super(props);
//this.state={inputfield: "no value"};
this.handleClick = this.handleClick.bind(this);
this.updateInputValue = this.updateInputValue.bind(this);
}
handleClick(){
console.log("trying to add picture url");
console.log("value of input field : "+this.state.inputfield);
}
updateInputValue(evt){
//console.log("input field updated with "+evt.target.value);
this.state={inputfield: evt.target.value};
}
render(){
var r;
r=<div><input type="text" id="addpixinputfield"
onChange={this.updateInputValue} />
<input type="button" value="add" id="addpix" onClick={this.handleClick}/>
</div>;
return r;
}
}
ваша ошибка связана с тем, что вы используете класс, а когда используете класс, нам нужно связать функции с этим, чтобы хорошо работать. во всяком случае, есть много уроков, почему мы должны "this" и что "this" делать в javascript.
если вы исправите кнопку отправки, это должно быть:
<button type="button" onClick={this.onSubmit.bind(this)} className="btn">Save</button>
а также если вы хотите показать значение этого ввода в консоли, вы должны использовать var title= this.title.value;
Вы можете получить входное значение без добавления функции onChange.
Просто добавьте элемент ввода a 'ref attr:
И затем используйте this.refs, чтобы получить входное значение, когда вам это нужно.
this.onSubmit.bind(this);