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.

Dave
quelle

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>

Dhiraj
quelle
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.

Räuber
quelle
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()}/>
Ilya Semenov
quelle
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

Ben Carp
quelle
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

Jack Lee
quelle
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>
  );
};
ettanany
quelle
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!

jmbertucci
quelle
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();
        }
      }} />
    );
  },
Kevin Suttle
quelle
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.

GAEfan
quelle
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

o01
quelle
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();
},
Pavel Hasala
quelle
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}
  />
);
Lane Rettig
quelle
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

Raza Gill
quelle
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'));
Alireza
quelle
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

Luke Watts
quelle
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()})}}
SHI1485
quelle
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();
}
Kirk Strobeck
quelle
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" />
Venkatesh Somu
quelle
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).

mpen
quelle
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('');

nichery
quelle
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.

Jack
quelle
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 }} />
})
Nijat Ahmadov
quelle
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"/>
  );
}} />
Dean Koštomaj
quelle
0

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

Arun Kumar
quelle