Как реагировать на настройку фокуса на конкретное текстовое поле после рендеринга компонента?
Документация, похоже, предлагает использовать ссылки, например:
Установите ref="nameInput"
в поле ввода в функции рендеринга, а затем вызовите:
this.refs.nameInput.getInputDOMNode().focus();
Но где я должен это назвать? Я пробовал несколько мест, но я не могу заставить его работать.
Вы должны сделать это в componentDidMount
и refs callback
. Что-то вроде этого
componentDidMount(){
this.nameInput.focus();
}
class App extends React.Component{
componentDidMount(){
this.nameInput.focus();
}
render() {
return(
<div>
<input
defaultValue="Won't focus"
/>
<input
ref={(input) => { this.nameInput = input; }}
defaultValue="will focus"
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="/react.js"></script>
<script src="/react-dom.js"></script>
<div id="app"></div>
@Dhiraj ответ правильный, и для удобства вы можете использовать опору autoFocus для автоматической фокусировки при подключении:
<input autoFocus name=...
Обратите внимание, что в jsx это autoFocus
(заглавная F) в отличие от простого старого html, который не чувствителен к регистру.
Начиная с React 0.15, наиболее сжатый способ:
<input ref={input => input && input.focus()}/>
Если вы просто хотите сделать автофокус в React, это просто.
<input autoFocus type="text" />
Если вам просто нужно знать, где разместить этот код, ответьте в компонентеDidMount().
v014.3
componentDidMount() {
this.refs.linkInput.focus()
}
В большинстве случаев вы можете прикрепить ссылку на DOM node и вообще не использовать findDOMNode.
Ознакомьтесь с документами API здесь: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
F
! (Примечание для себя и других, а не для ответчика).
Я просто столкнулся с этой проблемой, и я использую response 15.0.1 15.0.2, и я использую синтаксис ES6 и не совсем понял, что мне нужно от других ответов, поскольку v.15 упали недели назад, а некоторые из свойств this.refs
устарели и удалены.
В общем, мне было нужно:
Я использую:
Я использовал autoFocus={true}
для первого <input />
на странице, чтобы при установке компонента он получал фокус.
Это заняло больше времени и было более запутанным. Я сохраняю код, который не имеет отношения к решению для краткости.
Мне нужно глобальное состояние, чтобы знать, должен ли я устанавливать фокус и отключать его, когда он был установлен, поэтому я не буду переустанавливать фокус, когда компоненты повторно отображаются (я буду использовать componentDidUpdate()
для проверки установки фокуса.)
Это может быть спроектировано так, как вы считаете нужным для вашего приложения.
{
form: {
resetFocus: false,
}
}
Компонент должен будет иметь свойство свойства resetfocus
и callBack, чтобы очистить свойство, если он завершит настройку фокуса на себя.
Также обратите внимание: я организовал мои создатели Action в отдельные файлы, в основном из-за моего проекта, довольно большого, и я хотел разбить их на более управляемые куски.
import { connect } from 'react-redux';
import MyField from '../presentation/MyField';
import ActionCreator from '../actions/action-creators';
function mapStateToProps(state) {
return {
resetFocus: state.form.resetFocus
}
}
function mapDispatchToProps(dispatch) {
return {
clearResetFocus() {
dispatch(ActionCreator.clearResetFocus());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyField);
import React, { PropTypes } form 'react';
export default class MyField extends React.Component {
// don't forget to .bind(this)
constructor(props) {
super(props);
this._handleRef = this._handleRef.bind(this);
}
// This is not called on the initial render so
// this._input will be set before this get called
componentDidUpdate() {
if(!this.props.resetFocus) {
return false;
}
if(this.shouldfocus()) {
this._input.focus();
this.props.clearResetFocus();
}
}
// When the component mounts, it will save a
// reference to itself as _input, which we'll
// be able to call in subsequent componentDidUpdate()
// calls if we need to set focus.
_handleRef(c) {
this._input = c;
}
// Whatever logic you need to determine if this
// component should get focus
shouldFocus() {
// ...
}
// pass the _handleRef callback so we can access
// a reference of this element in other component methods
render() {
return (
<input ref={this._handleRef} type="text" />
);
}
}
Myfield.propTypes = {
clearResetFocus: PropTypes.func,
resetFocus: PropTypes.bool
}
Общая идея заключается в том, что каждое поле формы, которое может иметь ошибку и быть сфокусированным, должно проверять себя и, если ему нужно установить фокус на себя.
Существует бизнес-логика, которая должна произойти, чтобы определить, является ли данное поле правильным полем для установки фокуса. Это не показано, потому что это будет зависеть от отдельного приложения.
При отправке формы этому событию необходимо установить флаг глобальной фокусировки resetfocus
в значение true. Затем, когда каждый компонент обновляется, он увидит, что он должен проверить, будет ли он получать фокус, и если это произойдет, отправьте событие на reset focus, чтобы другие элементы не нуждались в проверке.
изменить
В качестве дополнительной заметки у меня была моя бизнес-логика в файле "utilities", и я только что экспортировал этот метод и назвал его в каждом методе shouldfocus()
.
Ура!
В документах React теперь есть раздел для этого. https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute
render: function() {
return (
<TextInput
ref={function(input) {
if (input != null) {
input.focus();
}
}} />
);
},
autofocus
при монтировании, я просто искал элемент, который оставался сфокусированным при вводе значения. Это отлично сработало для этого сценария. (используя реакцию 15)
Это правильный способ, как с автофокусом. Когда вы используете callback вместо строки в качестве значения ref, он вызывается автоматически. Вы получили свою ссылку доступнее, чем без необходимости прикасаться к DOM с помощью getDOMNode
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._input.focus();
},
Ref. @Прокомментируйте ответ @Dhiraj; альтернативой является использование функции обратного вызова атрибута ref на визуализируемом элементе (после того, как компонент сначала отобразит):
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
Uncaught TypeError: Cannot read property 'focus' of null
component && React.findDomNode...
Подробнее об этом читайте здесь: facebook.github.io/react/docs/…
Это не лучший ответ. Начиная с v0.13, this.refs
может быть недоступен до запуска AFTER componentDidMount()
в некоторых нечетных случаях.
Просто добавьте тег autoFocus
в поле ввода, как показано выше, FakeRainBrigand.
<input autofocus>
не будут вести себя хорошо
Вам не нужен getInputDOMNode
?? в этом случае...
Просто получите ref
и focus()
когда компонент будет смонтирован - componentDidMount...
import React from 'react';
import { render } from 'react-dom';
class myApp extends React.Component {
componentDidMount() {
this.nameInput.focus();
}
render() {
return(
<div>
<input ref={input => { this.nameInput = input; }} />
</div>
);
}
}
ReactDOM.render(<myApp />, document.getElementById('root'));
Вы можете поместить этот вызов метода внутри функции рендеринга. Или внутри метода жизненного цикла componentDidUpdate
Обратите внимание, что ни один из этих ответов не работал для меня с компонентом TextField для материала и пользовательского интерфейса. Как установить фокусировку на материале TextField? Мне пришлось перепрыгнуть через несколько обручей, чтобы заставить это работать:
const focusUsernameInputField = input => {
if (input) {
setTimeout(() => {input.focus()}, 100);
}
};
return (
<TextField
hintText="Username"
floatingLabelText="Username"
ref={focusUsernameInputField}
/>
);
focus()
должен быть отложен до конца анимации.
Автофокус работал лучше всего для меня. Мне нужно было изменить текст на вход с двойным щелчком, поэтому я закончил:
<input autoFocus onFocus={this.setCaretToEnd} value={this.state.editTodo.value} onDoubleClick={this.updateTodoItem} />
ПРИМЕЧАНИЕ. Чтобы устранить проблему, когда React размещает курсор в начале текста, используйте этот метод:
setCaretToEnd(event) {
var originalText = event.target.value;
event.target.value = '';
event.target.value = originalText;
}
Найдено здесь: https://coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js
Основное преимущество React в качестве основы заключается в том, что код может быть написан описательно, а не обязательно. Это важно - это облегчает понимание кода. Когда вы используете Ref, вы делаете свой код более обязательным.
В большинстве случаев достаточно использовать атрибут autoFocus.
<input type="text" autoFocus />
Возможно, вы захотите переместить фокус с одного элемента на другой, в соответствии с определенной логикой (например, перейти к следующему полю, когда было набрано ожидаемое количество символов). Проблема с атрибутом autoFocus заключается в том, что он может устанавливать фокус только при первом рендеринге компонента (монтировании). Так что просто изменение значения атрибута с true на false не будет иметь никакого эффекта.
Решение состоит в том, чтобы использовать атрибут ключа для повторного монтирования элемента при каждом изменении фокуса. Если мы это сделаем, мы можем рассматривать качество фокусировки как контролируемое.
class InputW extends Component {
state = {
value: ""
isFocused: false
}
handleChange = e => {
this.setState({ value: e.target.value, isFocused: true })
}
deFocus = () => this.setState({isFocused: false})
render(){
return (
<input
onChange={this.handleChange}
value={this.state.value}
autoFocus={this.state.isFocused}
key={this.state.isFocused}
onBlur={this.deFocus}
/>
)
}
}
Пример 1 - нажатие кнопки приводит к фокусировке ввода, а ввод 3 символов приводит к расфокусировке. Пример 2 - ввод перемещает фокус на следующий элемент поля.
У меня такая же проблема, но у меня тоже есть анимация, поэтому мой коллега предлагает использовать window.requestAnimationFrame
это атрибут ref моего элемента:
ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
Самый простой ответ - добавить ref = "some name" во входном текстовом элементе и вызвать функцию ниже.
componentDidMount(){
this.refs.field_name.focus();
}
// here field_name is ref name.
<input type="text" ref="field_name" />
Предупреждение: ReactDOMComponent: не получить доступ к .getDOMNode() DOM node; вместо этого используйте node напрямую. Этот DOM node отображался
App
.
Должно быть
componentDidMount: function () {
this.refs.nameInput.focus();
}
Попробовав множество вариантов, описанных выше, безуспешно, я обнаружил, что это было так, как будто я disabling
а затем enabling
ввод, что приводило к потере фокуса.
У меня был sendingAnswer
который sendingAnswer
бы ввод, пока я опрашивал бэкэнд.
<Input
autoFocus={question}
placeholder={
gettingQuestion ? 'Loading...' : 'Type your answer here...'
}
value={answer}
onChange={event => dispatch(updateAnswer(event.target.value))}
type="text"
autocomplete="off"
name="answer"
// disabled={sendingAnswer} <-- Causing focus to be lost.
/>
Как только я удалил отключенную опору, все снова заработало.
Прочитайте почти все ответы, но не увидели getRenderedComponent().props.input
Задайте свой текстовый ввод refs
this.refs.username.getRenderedComponent().props.input.onChange('');
В React 16.3 добавлен новый удобный способ справиться с этим путем создания ссылки на конструктор компонента и использования его, как показано ниже:
class MyForm extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focus(); // one important change here is that we need to access the element via current.
}
render() {
// instead of using arrow function, the created ref can be used directly.
return(
<div>
<input ref={this.textInput} />
</div>
);
}
}
Для более подробной информации, вы можете проверить эту статью в блоге React.
Также может быть сделано в компонентеDidMount, поскольку он вызывается сразу после рендеринга компонента с помощью
ReactDOM.findDOMNode(this.refs.item).focus();
<input type="text" ref='item'/>
Обновленную версию вы можете проверить здесь
componentDidMount() {
// Focus to the input as html5 autofocus
this.inputRef.focus();
}
render() {
return <input type="text" ref={(input) => { this.inputRef = input }} />
})