В React ES6, почему поле ввода теряет фокус после ввода символа?
В моем компоненте ниже поле ввода теряет фокус после ввода символа. При использовании Chrome Inspector похоже, что вся форма повторно отображается, а не только атрибут value поля ввода при вводе.
Я не получаю никаких ошибок ни от eslint, ни от Chrome Inspector.
Отправка самой формы работает так же, как и фактическое поле ввода, когда оно расположено либо в возврате рендеринга, либо при импорте в виде отдельного компонента, но не в том, как я его кодировал ниже.
Почему это так?
Компонент главной страницы
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionPost from '../redux/action/actionPost';
import InputText from './form/InputText';
import InputSubmit from './form/InputSubmit';
class _PostSingle extends Component {
constructor(props, context) {
super(props, context);
this.state = {
post: {
title: '',
},
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(event) {
this.setState({
post: {
title: event.target.value,
},
});
}
onSubmit(event) {
event.preventDefault();
this.props.actions.postCreate(this.state.post);
this.setState({
post: {
title: '',
},
});
}
render() {
const onChange = this.onChange;
const onSubmit = this.onSubmit;
const valueTitle = this.state.post.title;
const FormPostSingle = () => (
<form onSubmit={onSubmit}>
<InputText name="title" label="Title" placeholder="Enter a title" onChange={onChange} value={valueTitle} />
<InputSubmit name="Save" />
</form>
);
return (
<main id="main" role="main">
<div className="container-fluid">
<FormPostSingle />
</div>
</main>
);
}
}
_PostSingle.propTypes = {
actions: PropTypes.objectOf(PropTypes.func).isRequired,
};
function mapStateToProps(state) {
return {
posts: state.posts,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actionPost, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(_PostSingle);
Компонент ввода текста
import React, { PropTypes } from 'react';
const InputText = ({ name, label, placeholder, onChange, value, error }) => {
const fieldClass = 'form-control input-lg';
let wrapperClass = 'form-group';
if (error && error.length > 0) {
wrapperClass += ' has-error';
}
return (
<div className={wrapperClass}>
<label htmlFor={name} className="sr-only">{label}</label>
<input type="text" id={name} name={name} placeholder={placeholder} onChange={onChange} value={value} className={fieldClass} />
{error &&
<div className="alert alert-danger">{error}</div>
}
</div>
);
};
InputText.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
value: PropTypes.string,
error: PropTypes.string,
};
InputText.defaultProps = {
value: null,
error: null,
};
export default InputText;
Отправить компонент кнопки
import React, { PropTypes } from 'react';
const InputSubmit = ({ name }) => {
const fieldClass = 'btn btn-primary btn-lg';
return (
<input type="submit" value={name} className={fieldClass} />
);
};
InputSubmit.propTypes = {
name: PropTypes.string,
};
InputSubmit.defaultProps = {
name: 'Submit',
};
export default InputSubmit;
Ответы
Ответ 1
Что происходит, это:
Когда происходит событие onChange, функция обратного вызова вызывает setState с новым значением title, которое передается в ваше текстовое поле в качестве реквизита. В этот момент React рендерит его заново, поэтому вы теряете фокус.
Моим первым предложением было бы предоставить ключи ваших компонентов, в частности форму и сам ввод. Ключи позволяют React сохранять идентичность компонентов посредством визуализации.
Редактировать:
См. Эту документацию по ключам: https://reactjs.org/docs/lists-and-keys.html#keys.
Ответ 2
это потому, что вы визуализируете форму в функции внутри render().
Каждый раз, когда изменяется ваше состояние /prop, функция возвращает новую форму. это заставило вас потерять фокус.
Попробуйте помещать то, что внутри функции в ваш рендеринг напрямую.
<main id="main" role="main">
<div className="container-fluid">
<FormPostSingle />
</div>
</main>
==== >
<main id="main" role="main">
<div className="container-fluid">
<form onSubmit={onSubmit}>
<InputText name="title" label="Title" placeholder="Enter a title" onChange={onChange} value={valueTitle} />
<InputSubmit name="Save" />
</form>
</div>
</main>
Ответ 3
Моя проблема заключалась в том, что он перерисовывался в компоненте без сохранения состояния в том же файле. Поэтому, как только я избавился от ненужного компонента без сохранения состояния и просто вставил код напрямую, у меня не было ненужных повторных отрисовок.
render(){
const NewSocialPost = () =>
<div className='new-post'>
<input
onChange={(e) => this.setState({ newSocialPost: e.target.value })}
value={this.state.newSocialPost}/>
<button onClick={() => this._handleNewSocialPost()}>Submit</button>
</div>
return (
<div id='social-post-page'>
<div className='post-column'>
<div className='posts'>
<Stuff />
</div>
<NewSocialPost />
</div>
<MoreStuff />
</div>
Ответ 4
Я новичок в React, и столкнулся с этой проблемой.
Вот что я сделал, чтобы решить:
- Сначала переместите все свои компоненты в папку компонентов, а затем импортируйте их туда, где вы хотите их использовать.
- Убедитесь, что все элементы формы имеют свойство
name
и id
- Убедитесь, что все компоненты по мере прохождения дерева получают уникальный
key
Кто-то умнее меня, возможно, скажет нам, почему мы можем пропустить первый шаг и, так сказать, все встроить, но это только помогло мне организовать код.
Я думаю, что реальная проблема заключается в том, что React переопределяет все (как уже было сказано), и иногда перерисовка происходит в родительском компоненте, который не имеет key
но нуждается в нем.
Моя проблема была в том, что компоненты ExpansionPanel
обернули мои пользовательские компоненты для ввода формы. Панели нужен key
также!
Надеюсь, это поможет кому-то еще, это сводило меня с ума!
Ответ 5
Ваша форма перезаписывается при вводе символа, потому что у вас есть метод onChange
, который изменяет состояние. Каждое изменение состояния заставляет форму перезапускать, и поэтому метод ввода теряет фокус.
Поскольку вы используете redux, лучшим способом было бы сохранить значение заголовка сообщения в объекте redux. Кроме того, вы можете захотеть использовать redux-form
для своей формы.
Чтобы получить значение ввода без re-rendering
, вам нужно использовать refs
.
Ответ 6
Я не уполномочен комментировать, тогда это должен быть ответ. У меня была похожая проблема, и ответ от Алекса Яна был решительным.
А именно у меня была эта функция
const DisplaySearchArea =()=>{return (arrayOfSearchFieldNames.map((element, index)=>{return(<div key ={index} className = {inputFieldStyle}><input placeholder= {arrayOfPlaceholders[index]} type="text" className='border-0'
value={this.state[element]}
onChange={e => {this.setState({ [element]: e.target.value }); console.log(e.target)}}
onMouseEnter={e=>e.target.focus()}/></div>)}))}
он работает нормально с FF, а не с Chrome, когда отображается как <DisplaySearchArea/>
Когда отображается как {...}, он работает с обоими. Код выглядит не так "красиво", но работает, мне уже сказали, что он склонен злоупотреблять лямбдами.
Ответ 7
Спасибо, Алекс. Таким образом, я решил свою проблему:
constructor(props, context) {
...
this.FormPostSingle = this.FormPostSingle.bind(this);
}
FormPostSingle() {
const onChange = this.onChange;
const onSubmit = this.onSubmit;
const valueTitle = this.state.post.title;
return (
<form onSubmit={onSubmit}>
<InputText name="title" label="Title" placeholder="Enter a title" onChange={onChange} value={valueTitle} />
<InputSubmit name="Save" />
</form> );
}
render() {
let FormPostSingle = this.FormPostSingle
return...
}