Wie kann man nach dem Rendern den Fokus auf ein Eingabefeld setzen?


629

Wie kann der Fokus nach dem Rendern der Komponente auf ein bestimmtes Textfeld gesetzt werden?

Die Dokumentation scheint die Verwendung von Referenzen vorzuschlagen, z.

Stellen Sie ref="nameInput"in der Renderfunktion mein Eingabefeld ein und rufen Sie dann auf:

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

Aber wo soll ich das nennen? Ich habe ein paar Orte ausprobiert, aber ich kann es nicht zum Laufen bringen.

Antworten:


669

Sie sollten es in componentDidMountund refs callbackstattdessen tun . Etwas wie das

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="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<div id="app"></div>


107
Dies ist die richtige Antwort, aber sie hat bei mir nicht funktioniert, da meine Komponente zuerst nichts rendert, bis auf eine andere Schaltfläche geklickt wird. Dies bedeutete, dass es bereits gemountet war, also musste ich this.refs.nameInput.getDOMNode (). Focus () hinzufügen; in componentDidUpdate anstelle von componentDidMount.
Dave

9
Warum setzt element.focus () beim Aufruf von element.focus () den Cursor an den Anfang der Eingabe? Ich habe diesen (was ich für einen halte) Fehler in meiner App gesehen, in Chrome, tatsächlich in einem <Textbereich>, und jetzt überprüfe ich Ihre Demos hier, es ist das gleiche.
Davnicwil

15
Warnung: React.findDOMNode ist veraltet. Bitte verwenden Sie stattdessen ReactDOM.findDOMNode von require ('react-dom').
André Pena

5
@ HuwDavies Ich denke, Sie würden es mit einem ref Callback-Attribut für das <input>Element tun . So etwas wie<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
Hermann

5
Warum verwenden wir nicht einfach ref = {(input) => {input.focus ()}} ? Diese Lösung funktioniert gut für mich.
HCLiu

841

Die Antwort von @ Dhiraj ist korrekt, und der Einfachheit halber können Sie die Autofokus-Requisite verwenden, um eine Eingabe beim Mounten automatisch fokussieren zu lassen:

<input autoFocus name=...

Beachten Sie, dass es in jsx autoFocus(Großbuchstabe F) im Gegensatz zu einfachem altem HTML ist, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird.


95
Beachten Sie, dass in jsx sein Auto F ocus (Kapital F) im Gegensatz zu einfacher alter html , die Groß- und Kleinschreibung ist.
Rauchrauch

8
Sehr gut, bin nach einer langen erfolglosen Suche hierher gekommen :) Zu Ihrer Information - Am Ende habe ich React.DOM.input verwendet ({Typ: 'Text', Standardwert: Inhalt, Autofokus: true, onFocus: Funktion (e) {e.target. wählen();} })
mlo55

4
Ich finde, dass der Autofokus nur beim Rendern der ersten Seite funktioniert. Sehen codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111. Die Eingabe sollte nach 3 Sekunden fokussiert sein.
Eric Andrew Lewis

45
+1 für diese Methode. Es ist erwähnenswert, dass hier nicht nur das unzuverlässige HTML5- autofocusAttribut verwendet wird, sondern auch das focus()DOM-Mount-In,react-dom sodass es ziemlich zuverlässig ist.
Aaron Beall

3
Nicht nur "zur Vereinfachung", sondern auch, wenn Ihre Komponente eine funktionale Komponente ist.
Phillyslick

167

Ab Reaktion 0.15 ist die prägnanteste Methode:

<input ref={input => input && input.focus()}/>

5
Dies behandelt auch die Szenarien außerhalb des anfänglichen Renderings, während dies bei Verwendung von Autofokus nicht der Fall ist.
Matt Stannett

Frage, wann wäre die Eingabe falsch? Ich beziehe mich auf den Ausdruck innerhalb der Pfeilfunktion.
JaeGeeTee

2
@JaeGeeTee ist null, bis die Komponente gemountet ist und / oder nachdem sie nicht gemountet wurde (ich weiß nicht mehr genau, was der Fall ist).
Ilya Semenov

12
Das einzige Problem dabei ist, dass es die Eingabe auf jedes erneute Rendern konzentriert, das möglicherweise nicht erwünscht ist.
Jaroslav Benc

Funktioniert in meinem Fall nicht (mit Ant Design- Eingabekomponente)
vsync

118

Konzentrieren Sie sich auf die Montierung

Wenn Sie ein Element beim Mounten (anfänglich rendern) nur fokussieren möchten, reicht eine einfache Verwendung des autoFocus-Attributs aus.

<input type="text" autoFocus />

Dynamischer Fokus

Um den Fokus dynamisch zu steuern, verwenden Sie eine allgemeine Funktion, um Implementierungsdetails vor Ihren Komponenten zu verbergen.

Reagieren Sie auf 16.8 + Funktionskomponente - useFocus hook

const FocusDemo = () => {

    const [inputRef, setInputFocus] = useFocus()

    return (
        <> 
            <button onClick={setInputFocus} >
               FOCUS
            </button>
            <input ref={inputRef} />
        </>
    )

}
const useFocus = () => {
    const htmlElRef = useRef(null)
    const setFocus = () => {htmlElRef.current &&  htmlElRef.current.focus()}

    return [ htmlElRef, setFocus ] 
}

Vollständige Demo

Reagieren Sie auf Komponenten der Klasse 16.3 + - useFocus

class App extends Component {
  constructor(props){
    super(props)
    this.inputFocus = utilizeFocus()
  }

  render(){
    return (
      <> 
          <button onClick={this.inputFocus.setFocus}>
             FOCUS
          </button>
          <input ref={this.inputFocus.ref}/>
      </>
    )
  } 
}
const utilizeFocus = () => {
    const ref = React.createRef()
    const setFocus = () => {ref.current &&  ref.current.focus()}

    return {setFocus, ref} 
}

Vollständige Demo


2
Diese Antwort enthält den richtigen Ansatz für React Hooks. Super! Es prüft nicht wie es ist in TypeScript, sondern eine (hässliche) Möglichkeit, damit es funktioniert: (1) (htmlElRef.current as any).focus()und (2) return {htmlElRef, setFocus}anstelle von Array.
Ahmed Fasih

@AhmedFasih, ich weiß, was Sie sagen, aber ich denke, dass dies für diesen Thread nicht möglich ist. Wenn Sie ein Objekt zurückgeben, ist es schwieriger, den Namen der Variablen zu steuern. Dies kann ein Problem sein, wenn Sie useFocusmehr als ein Element verwenden möchten .
Ben Carp

8
Hier ist useFocusin Typoskript geschrieben. gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573
Ben Carp

2
Super saftig, danke !!! Wow, ich wusste nichts über konstante Behauptungen (die as constdu hast), sehr lehrreich!
Ahmed Fasih

@BenCarp Kleiner Vorschlag für Haken, könnte besser sein, die setin die zweite Position zu bringen wie const [inputRef, setInputFocus] = useFocus(). Dies entspricht useState mehr. Erst das Objekt, dann der Setter dieses Objekts
Rubanov

59

Wenn Sie in React nur den Autofokus aktivieren möchten, ist dies ganz einfach.

<input autoFocus type="text" />

Wenn Sie nur wissen möchten, wo Sie diesen Code ablegen sollen, finden Sie die Antwort in componentDidMount ().

v014.3

componentDidMount() {
    this.refs.linkInput.focus()
}

In den meisten Fällen können Sie dem DOM-Knoten eine Referenz hinzufügen und die Verwendung von findDOMNode überhaupt vermeiden.

Lesen Sie die API-Dokumente hier: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode


9
Und denken Sie daran, das zu kapitalisieren F! (Hinweis für sich selbst und andere, nicht für den Antwortenden).
2540625

29

Reagieren 16.3 wurde eine neue bequeme Methode hinzugefügt, um dies zu handhaben, indem im Konstruktor der Komponente eine Referenz erstellt und wie folgt verwendet wird:

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

Weitere Details können Sie überprüfen diesem Artikel im React-Blog.

Aktualisieren:

Ab Reaktion 16.8 kann der useRefHaken in Funktionskomponenten verwendet werden, um das gleiche Ergebnis zu erzielen:

import React, { useEffect, useRef } from 'react';

const MyForm = () => {
  const textInput = useRef(null);

  useEffect(() => {
    textInput.current.focus();
  }, []);

  return (
    <div>
      <input ref={textInput} />
    </div>
  );
};

26

Ich bin gerade auf dieses Problem gestoßen und verwende reag 15.0.1 15.0.2 und ich verwende die ES6-Syntax und habe aus den anderen Antworten nicht ganz das bekommen, was ich brauchte, da v.15 vor Wochen und einige der this.refsEigenschaften gelöscht wurden wurden veraltet und entfernt .

Im Allgemeinen brauchte ich:

  1. Fokussieren Sie das erste Eingabe- (Feld-) Element, wenn die Komponente bereitgestellt wird
  2. Fokussieren Sie das erste Eingabe- (Feld-) Element mit einem Fehler (nach dem Senden).

Ich benutze:

  • Reaktionsbehälter / Präsentationskomponente
  • Redux
  • React-Router

Fokussieren Sie das erste Eingabeelement

Ich habe autoFocus={true}auf der ersten <input />Seite verwendet, damit die Komponente beim Mounten den Fokus erhält.

Fokussieren Sie das erste Eingabeelement mit einem Fehler

Dies dauerte länger und war komplizierter. Ich halte Code fern, der für die Lösung der Kürze halber nicht relevant ist.

Redux Store / State

Ich benötige einen globalen Status, um zu wissen, ob ich den Fokus festlegen und deaktivieren soll, wenn er festgelegt wurde. Daher setze ich den Fokus nicht immer wieder neu, wenn die Komponenten neu gerendert werden (ich werde ihn verwenden componentDidUpdate(), um den Fokus festzulegen. )

Dies kann so gestaltet werden, wie Sie es für Ihre Anwendung für richtig halten.

{
    form: {
        resetFocus: false,
    }
}

Containerkomponente

Für die Komponente müssen die resetfocusEigenschaft und ein CallBack festgelegt sein, um die Eigenschaft zu löschen, wenn der Fokus auf sich selbst gelegt wird.

Beachten Sie auch, dass ich meine Action Creators in separate Dateien organisiert habe, hauptsächlich weil mein Projekt ziemlich groß ist und ich sie in überschaubarere Teile aufteilen wollte.

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

Präsentationskomponente

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
}

Überblick

Die allgemeine Idee ist, dass jedes Formularfeld, das einen Fehler aufweisen und fokussiert sein könnte, sich selbst überprüfen muss und ob es sich auf sich selbst konzentrieren muss.

Es muss eine Geschäftslogik vorhanden sein, um festzustellen, ob das angegebene Feld das richtige Feld ist, auf das der Fokus gesetzt werden soll. Dies wird nicht angezeigt, da es von der jeweiligen Anwendung abhängt.

Wenn ein Formular gesendet wird, muss dieses Ereignis das globale Fokusflag resetFocusauf true setzen. Wenn sich dann jede Komponente selbst aktualisiert, wird überprüft, ob sie den Fokus erhält. Wenn dies der Fall ist, wird das Ereignis ausgelöst, um den Fokus zurückzusetzen, damit andere Elemente nicht weiter prüfen müssen.

Bearbeiten Als Randnotiz hatte ich meine Geschäftslogik in einer "Dienstprogramm" -Datei und habe die Methode einfach exportiert und in jeder aufgerufenshouldfocus() Methode .

Prost!


25

Die React-Dokumente haben jetzt einen Abschnitt dafür. 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
Ich denke, dies ist eine gute Möglichkeit, dies für dieses spezielle Szenario zu tun.
fabio.sussetto

Ich musste nicht autofocusmontieren, sondern suchte nur nach dem Element, das bei der Eingabe eines Werts fokussiert bleiben sollte. Dies funktionierte perfekt für dieses Szenario. (mit Reaktion 15)
Matt Parrilla

13

Dies ist nicht mehr die beste Antwort. Ab Version 0.13 ist this.refses componentDidMount()in einigen Fällen möglicherweise erst verfügbar, nachdem AFTER ausgeführt wurde.

autoFocusFügen Sie einfach das Tag zu Ihrem Eingabefeld hinzu, wie oben von FakeRainBrigand gezeigt.


4
Mehrere <input autofocus>Felder verhalten sich nicht gut
ᆼ ᆺ ᆼ

4
Natürlich nicht. Nur ein Fokus pro Seite. Wenn Sie mehrere Autofokusse haben, sollten Sie Ihren Code und Ihre Absichten überprüfen.
GAEfan

2
@ Daves Frage war über das Setzen des Fokus auf ein <input>After-Rendering
ᆼ ᆺ ᆼ

1
Gibt es im Autofokus eine Möglichkeit, das Öffnen der iOS-Tastatur zu erzwingen?
Remi Sture

1
@ RemiSture gleiche Fragen. Hat jemand eine Lösung für dieses Problem?
Nam Lê Quý

12

Ref. @ Daves Kommentar zu @ Dhirajs Antwort; Eine Alternative besteht darin, die Rückruffunktion des ref-Attributs für das gerenderte Element zu verwenden (nachdem eine Komponente zum ersten Mal gerendert wurde):

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

Mehr Info


Als ich das ausprobierte, bekam ich:Uncaught TypeError: Cannot read property 'focus' of null
reectrix

1
Sie müssen den Parameter auf Null setzen. Er ist null, wenn die Komponente nicht bereitgestellt ist. Also einfach component && React.findDomNode.... Lesen Sie hier mehr darüber: facebook.github.io/react/docs/…
Per Wiklander

12

Dies ist der richtige Weg, um Autofokus. Wenn Sie Callback anstelle von String als Referenzwert verwenden, wird dieser automatisch aufgerufen. Sie haben Ihre Referenz verfügbar, ohne das DOM mit berühren zu müssengetDOMNode

render: function() {
  return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
  this._input.focus();
},

2
Was ist mit einer kontrollierten Form?
Pixel 67

@ Pixel67 Auch. Sie können Verweise auf Elemente, aber auch auf Komponenten festlegen. Aber Sie müssen sich dessen bewusst sein, wenn Sie damit arbeiten. Sie werden also nicht versuchen, auf den Wert der Eingabe zuzugreifen, wenn Sie einen Verweis auf React.Component festlegen, der die HTML-Eingabe umschließt.
Pavel Hasala

10

Beachten Sie, dass keine dieser Antworten bei mir mit einer Material-UI-TextField-Komponente funktioniert hat . Per Wie setze ich den Fokus auf ein materialUI TextField? Ich musste durch einige Reifen springen, um dies zum Laufen zu bringen:

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

return (
  <TextField
    hintText="Username"
    floatingLabelText="Username"
    ref={focusUsernameInputField}
  />
);

2
Wenn Ihre Komponente animiert wird, muss der Aufruf von focus()bis zum Ende der Animation verzögert werden.
Adriendenat

9

Sie können diesen Methodenaufruf in die Renderfunktion einfügen. Oder innerhalb der Lebenszyklusmethode,componentDidUpdate


1
componentDidUpdate hat in meinem Fall funktioniert. Ich musste den Fokus auf eine bestimmte Schaltfläche setzen, nachdem das Rendern aufgerufen wurde.
FariaC

8

Du brauchst nicht getInputDOMNode?? in diesem Fall...

Holen Sie sich einfach das refund focus()es, wenn die Komponente bereitgestellt wird - 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'));

5

AutoFocus hat bei mir am besten funktioniert. Ich musste einen Text in eine Eingabe mit diesem Text per Doppelklick ändern, damit ich am Ende Folgendes erhielt:

<input autoFocus onFocus={this.setCaretToEnd} value={this.state.editTodo.value} onDoubleClick={this.updateTodoItem} />

HINWEIS: Um das Problem zu beheben, bei dem React das Caret am Anfang des Textes platziert, verwenden Sie diese Methode:

setCaretToEnd(event) {
    var originalText = event.target.value;
    event.target.value = '';
    event.target.value = originalText;
}

Hier zu finden: https://coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js


3

Ich habe das gleiche Problem, aber ich habe auch einige Animationen, daher schlägt mein Kollege vor, window.requestAnimationFrame zu verwenden

Dies ist das Ref-Attribut meines Elements:

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

2

Warnung: ReactDOMComponent: Greifen Sie nicht auf .getDOMNode () eines DOM-Knotens zu. Verwenden Sie stattdessen den Knoten direkt. Dieser DOM-Knoten wurde von gerendert App.

Sollte sein

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

2

Die einfachste Antwort ist, das ref = "irgendeinen Namen" in das Eingabetextelement einzufügen und die folgende Funktion aufzurufen.

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

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

2

Um den Fokus auf ein neu erstelltes Element zu verschieben, können Sie die ID des Elements im Status speichern und zum Festlegen verwenden autoFocus. z.B

export default class DefaultRolesPage extends React.Component {

    addRole = ev => {
        ev.preventDefault();
        const roleKey = this.roleKey++;
        this::updateState({
            focus: {$set: roleKey},
            formData: {
                roles: {
                    $push: [{
                        id: null,
                        name: '',
                        permissions: new Set(),
                        key: roleKey,
                    }]
                }
            }
        })
    }

    render() {
        const {formData} = this.state;

        return (
            <GridForm onSubmit={this.submit}>
                {formData.roles.map((role, idx) => (
                    <GridSection key={role.key}>
                        <GridRow>
                            <GridCol>
                                <label>Role</label>
                                <TextBox value={role.name} onChange={this.roleName(idx)} autoFocus={role.key === this.state.focus}/>
                            </GridCol>
                        </GridRow>
                    </GridSection>
                ))}
            </GridForm>
        )
    }
}

Auf diese Weise wird keines der Textfelder auf das Laden von Seiten fokussiert (wie ich es möchte). Wenn Sie jedoch auf die Schaltfläche "Hinzufügen" klicken, um einen neuen Datensatz zu erstellen, wird dieser neue Datensatz fokussiert.

Da autoFocusdie Komponente erst wieder "ausgeführt" wird, wenn die Komponente erneut bereitgestellt wird, muss ich mich nicht um das Deaktivieren kümmern this.state.focus(dh sie stiehlt den Fokus nicht mehr zurück, wenn ich andere Status aktualisiere).


1

Lies fast die ganze Antwort, sah aber keine getRenderedComponent().props.input

Stellen Sie Ihre Texteingabe-Refs ein

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


Bitte klären Sie Ihre Antwort im Zusammenhang mit ihrem Code weiter.
Jimmy Smith

1

Nachdem ich viele der oben genannten Optionen ohne Erfolg ausprobiert hatte, stellte ich fest, dass es so war, wie ich war, disablingund dann enablingdie Eingabe, die dazu führte, dass der Fokus verloren ging.

Ich hatte eine Requisite, sendingAnswerdie die Eingabe deaktivieren würde, während ich das Backend abfragte.

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

Nachdem ich die behinderte Requisite entfernt hatte, fing alles wieder an zu funktionieren.


0

Aktualisierte Version können Sie hier überprüfen

componentDidMount() {

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

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

0

Da es viele Gründe für diesen Fehler gibt, dachte ich, dass ich auch das Problem posten würde, mit dem ich konfrontiert war. Für mich war das Problem, dass ich meine Eingaben als Inhalt einer anderen Komponente gerendert habe.

export default ({ Content }) => {
  return (
  <div className="container-fluid main_container">
    <div className="row">
      <div className="col-sm-12 h-100">
        <Content />                                 // I rendered my inputs here
      </div>
    </div>
  </div>
  );
}

So habe ich die obige Komponente genannt:

<Component Content={() => {
  return (
    <input type="text"/>
  );
}} />

0

Entsprechend der aktualisierten Syntax können Sie verwenden this.myRref.current.focus()

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.