Установить фокус на ввод после рендера

415

Как реагировать на настройку фокуса на конкретное текстовое поле после рендеринга компонента?

Документация, похоже, предлагает использовать ссылки, например:

Установите ref="nameInput" в поле ввода в функции рендеринга, а затем вызовите:

this.refs.nameInput.getInputDOMNode().focus(); 

Но где я должен это назвать? Я пробовал несколько мест, но я не могу заставить его работать.

Теги:

22 ответа

495
Лучший ответ

Вы должны сделать это в 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>
  • 90
    Это правильный ответ, но он не работал для меня, так как мой компонент сначала ничего не отображает, пока не нажата другая кнопка. Это означало, что он был уже смонтирован, поэтому мне пришлось добавить this.refs.nameInput.getDOMNode (). Focus (); в componentDidUpdate вместо componentDidMount.
  • 7
    Почему, когда вызывается element.focus (), он помещает курсор в начало ввода? Я видел эту (что я считаю) ошибку в моем приложении, в chrome, на самом деле в <textarea>, и теперь проверяю ваши демки здесь, это то же самое.
Показать ещё 12 комментариев
589

@Dhiraj ответ правильный, и для удобства вы можете использовать опору autoFocus для автоматической фокусировки при подключении:

<input autoFocus name=...

Обратите внимание, что в jsx это autoFocus (заглавная F) в отличие от простого старого html, который не чувствителен к регистру.

  • 81
    Обратите внимание, что в jsx его автоматический F ocus (заглавная F) отличается от простого старого html, который не учитывает регистр.
  • 6
    Очень хорошо, попал сюда после долгого бесплодного поиска :) К вашему сведению - я использовал React.DOM.input ({type: 'text', defaultValue: content, autoFocus: true, onFocus: function (e) {e.target. Выбрать();} })
Показать ещё 9 комментариев
134

Начиная с React 0.15, наиболее сжатый способ:

<input ref={input => input && input.focus()}/>
  • 4
    Это также обрабатывает сценарии вне начального рендеринга, тогда как использование только автоматической фокусировки - нет.
  • 0
    вопрос, когда ввод будет ложным? Я имею в виду выражение внутри функции стрелки.
Показать ещё 2 комментария
50

Если вы просто хотите сделать автофокус в 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

  • 7
    И не забывайте использовать этот F ! (Примечание для себя и других, а не для ответчика).
23

Я просто столкнулся с этой проблемой, и я использую response 15.0.1 15.0.2, и я использую синтаксис ES6 и не совсем понял, что мне нужно от других ответов, поскольку v.15 упали недели назад, а некоторые из свойств this.refs устарели и удалены.

В общем, мне было нужно:

  • Сфокусируйте первый элемент ввода (поле), когда компонент монтирует
  • Сфокусируйте первый элемент ввода (поле) с ошибкой (после отправки)

Я использую:

  • Реакция компонента контейнера/презентации
  • Redux
  • Реагировать-маршрутизатор

Фокусировка первого элемента ввода

Я использовал autoFocus={true} для первого <input /> на странице, чтобы при установке компонента он получал фокус.

Сконцентрируйте первый элемент ввода с ошибкой

Это заняло больше времени и было более запутанным. Я сохраняю код, который не имеет отношения к решению для краткости.

Redux Store/State

Мне нужно глобальное состояние, чтобы знать, должен ли я устанавливать фокус и отключать его, когда он был установлен, поэтому я не буду переустанавливать фокус, когда компоненты повторно отображаются (я буду использовать 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().

Ура!

22

В документах 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();
        }
      }} />
    );
  },
  • 1
    Я думаю, что это хороший способ сделать это для этого конкретного сценария.
  • 0
    Мне не нужно было autofocus при монтировании, я просто искал элемент, который оставался сфокусированным при вводе значения. Это отлично сработало для этого сценария. (используя реакцию 15)
11

Это правильный способ, как с автофокусом. Когда вы используете callback вместо строки в качестве значения ref, он вызывается автоматически. Вы получили свою ссылку доступнее, чем без необходимости прикасаться к DOM с помощью getDOMNode

render: function() {
  return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
  this._input.focus();
},
  • 1
    как насчет контролируемой формы?
  • 0
    @ pixel67 Также. Вы можете установить ссылку на элементы, но и компоненты. Но вы должны знать об этом при работе с ним. Таким образом, вы не будете пытаться получить доступ к .value ввода, если вы установите ссылку на React.Component, который обернет ввод html.
10

Ref. @Прокомментируйте ответ @Dhiraj; альтернативой является использование функции обратного вызова атрибута ref на визуализируемом элементе (после того, как компонент сначала отобразит):

<input ref={ function(component){ React.findDOMNode(component).focus();} } />

Подробнее

  • 0
    Когда я попробовал это, я получил: Uncaught TypeError: Cannot read property 'focus' of null
  • 1
    Вы должны проверить параметр на null, он будет нулевым, когда компонент не смонтирован. Итак, простой component && React.findDomNode... Подробнее об этом читайте здесь: facebook.github.io/react/docs/…
9

Это не лучший ответ. Начиная с v0.13, this.refs может быть недоступен до запуска AFTER componentDidMount() в некоторых нечетных случаях.

Просто добавьте тег autoFocus в поле ввода, как показано выше, FakeRainBrigand.

  • 4
    Несколько полей <input autofocus> не будут вести себя хорошо
  • 4
    Конечно, нет. Только один фокус на странице. Если у вас есть несколько автофокусов, вы должны проверить свой код и намерения.
Показать ещё 2 комментария
7

Вам не нужен 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'));
7

Вы можете поместить этот вызов метода внутри функции рендеринга. Или внутри метода жизненного цикла componentDidUpdate

  • 1
    componentDidUpdate - это то, что сработало для моего случая. Мне нужно было установить фокус на определенной кнопке после вызова рендера.
6

Обратите внимание, что ни один из этих ответов не работал для меня с компонентом TextField для материала и пользовательского интерфейса. Как установить фокусировку на материале TextField? Мне пришлось перепрыгнуть через несколько обручей, чтобы заставить это работать:

const focusUsernameInputField = input => {
  if (input) {
    setTimeout(() => {input.focus()}, 100);
  }
};

return (
  <TextField
    hintText="Username"
    floatingLabelText="Username"
    ref={focusUsernameInputField}
  />
);
  • 1
    Похоже, если ваш компонент анимируется, вызов focus() должен быть отложен до конца анимации.
3

Автофокус работал лучше всего для меня. Мне нужно было изменить текст на вход с двойным щелчком, поэтому я закончил:

<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

2

Вам не нужно использовать Ref

Основное преимущество 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 - ввод перемещает фокус на следующий элемент поля.

2

У меня такая же проблема, но у меня тоже есть анимация, поэтому мой коллега предлагает использовать window.requestAnimationFrame

это атрибут ref моего элемента:

ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
2

Самый простой ответ - добавить ref = "some name" во входном текстовом элементе и вызвать функцию ниже.

componentDidMount(){
   this.refs.field_name.focus();
}
// here field_name is ref name.

<input type="text" ref="field_name" />
2

Предупреждение: ReactDOMComponent: не получить доступ к .getDOMNode() DOM node; вместо этого используйте node напрямую. Этот DOM node отображался App.

Должно быть

componentDidMount: function () {
  this.refs.nameInput.focus();
}
1

Попробовав множество вариантов, описанных выше, безуспешно, я обнаружил, что это было так, как будто я 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.
/>

Как только я удалил отключенную опору, все снова заработало.

1

Прочитайте почти все ответы, но не увидели getRenderedComponent().props.input

Задайте свой текстовый ввод refs

this.refs.username.getRenderedComponent().props.input.onChange('');

  • 0
    Пожалуйста, уточните свой ответ в контексте их кода.
0

В 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.

0

Также может быть сделано в компонентеDidMount, поскольку он вызывается сразу после рендеринга компонента с помощью

ReactDOM.findDOMNode(this.refs.item).focus();

<input type="text" ref='item'/>
0

Обновленную версию вы можете проверить здесь

componentDidMount() {

    // Focus to the input as html5 autofocus
    this.inputRef.focus();

}
render() {
    return <input type="text" ref={(input) => { this.inputRef = input }} />
})

Ещё вопросы

Сообщество Overcoder
Наверх
Меню