Come impostare lo stato attivo su un campo di input dopo il rendering?


629

Qual è il modo di reagire per mettere a fuoco un particolare campo di testo dopo il rendering del componente?

La documentazione sembra suggerire l'uso di refs, ad esempio:

Impostare ref="nameInput"sul mio campo di input nella funzione di rendering, quindi chiamare:

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

Ma dove dovrei chiamare questo? Ho provato alcuni posti ma non riesco a farlo funzionare.

Risposte:


669

Dovresti farlo dentro componentDidMounte refs callbackinvece. Qualcosa come questo

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
Questa è la risposta corretta, ma non ha funzionato per me in quanto il mio componente non esegue il rendering prima di fare clic su un altro pulsante. Ciò significava che era già montato, quindi ho dovuto aggiungere this.refs.nameInput.getDOMNode (). Focus (); in componentDidUpdate anziché componentDidMount.
Dave,

9
Perché, quando viene chiamato element.focus (), posiziona il cursore all'inizio dell'input? Ho visto questo (quello che considero un bug) nella mia app, in Chrome, in realtà in <textarea> e ora controllare le tue demo qui è lo stesso.
davnicwil,

15
Avviso: React.findDOMNode è obsoleto. Utilizzare invece ReactDOM.findDOMNode da request ('reazioni-dom').
André Pena,

5
@HuwDavies immagino lo faresti con un rif richiamata attributo sul <input>elemento. Qualcosa di simile<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
herman,

5
Perché non utilizziamo semplicemente ref = {(input) => {input.focus ()}} ? Questa soluzione funziona bene per me.
HCLiu,

841

La risposta di @ Dhiraj è corretta e, per comodità, puoi usare il puntello autoFocus per mettere automaticamente a fuoco un input quando montato:

<input autoFocus name=...

Si noti che in jsx è autoFocus(maiuscola F) a differenza del semplice vecchio HTML che non fa distinzione tra maiuscole e minuscole.


95
Si noti che in jsx il suo F ocus automatico (maiuscola F) a differenza del semplice html che non fa distinzione tra maiuscole e minuscole.
Prauchfuss,

8
Molto bene, sono arrivato qui dopo una lunga e inutile ricerca :) Cordiali saluti - Ho finito con React.DOM.input ({type: 'text', defaultValue: content, autoFocus: true, onFocus: function (e) {e.target. select ();}})
mlo55

4
Trovo che autoFocus funzioni solo sul rendering della prima pagina. Vedi codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111 l'input deve essere focalizzato dopo 3 secondi.
Eric Andrew Lewis,

45
+1 per questo metodo. Vale la pena ricordare che questo non solo usa l' autofocusattributo HTML5 inaffidabile , ma in realtà utilizza focus()su DOM mount,react-dom quindi è abbastanza affidabile.
Aaron Beall

3
Non solo "per comodità", ma anche se il componente è un componente funzionale.
Phillyslick,

167

A partire da React 0.15 , il metodo più conciso è:

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

5
Questo gestisce anche gli scenari al di fuori del rendering iniziale, mentre non lo fa solo l'uso di AutoFocus.
Matt Stannett,

domanda, quando input sarebbe falso? Mi riferisco all'espressione all'interno della funzione freccia.
JaeGeeTee,

2
@JaeGeeTee è null fino a quando il componente non viene montato e / o dopo che è stato smontato (non ricordo per certo quale sia il caso).
Ilya Semenov,

12
L'unico problema è che concentra l'input su qualsiasi nuovo rendering che potrebbe non essere desiderato.
Jaroslav Benc

Nel mio caso non funziona (utilizzando il componente di input di Ant Design )
vsync,

118

Focus sul monte

Se vuoi solo mettere a fuoco un elemento quando monta (inizialmente il rendering) farà un semplice uso dell'attributo autoFocus.

<input type="text" autoFocus />

Messa a fuoco dinamica

per controllare la messa a fuoco in modo dinamico, utilizzare una funzione generale per nascondere i dettagli di implementazione dai componenti.

Reagisci 16.8 + Componente funzionale: usa il gancio Focus

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 ] 
}

Demo completa

Reagisci 16.3 + Componenti di classe - utilizzaFocus

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

Demo completa


2
Questa risposta contiene l'approccio giusto per React Hooks. Super! Non esegue il controllo ortografico così com'è in TypeScript ma un (brutto) modo per farlo funzionare: (1) (htmlElRef.current as any).focus()e (2) return {htmlElRef, setFocus}invece di array.
Ahmed Fasih,

@AhmedFasih, sono consapevole di quello che stai dicendo, ma penso che sia fuori portata per questo thread. Se si restituisce un oggetto, diventa più difficile controllare il nome della variabile, il che potrebbe essere un problema se si desidera utilizzare useFocusper più di un elemento.
Ben Carp

8
Qui è useFocusscritto in dattiloscritto. gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573
Ben Carp

2
Super succosa, grazie !!! Wow, non sapevo delle asserzioni const (che as consthai), molto educative!
Ahmed Fasih,

@BenCarp Piccolo suggerimento per i ganci, potrebbe essere meglio metterlo setnella seconda posizione come const [inputRef, setInputFocus] = useFocus(). Questo corrisponde a Usa lo stato di più. Prima l'oggetto, poi il setter di quell'oggetto
Rubanov,

59

Se vuoi solo fare l'autofocus in React, è semplice.

<input autoFocus type="text" />

Mentre se vuoi solo sapere dove inserire quel codice, la risposta è in componentDidMount ().

v014.3

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

Nella maggior parte dei casi, è possibile collegare un riferimento al nodo DOM ed evitare di utilizzare findDOMNode.

Leggi i documenti API qui: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode


9
E ricorda di capitalizzare questo F! (Nota per sé e per gli altri, non per chi risponde).
2540625,

29

React 16.3 ha aggiunto un nuovo modo conveniente per gestirlo creando un ref nel costruttore del componente e utilizzandolo come di seguito:

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

Per maggiori dettagli, puoi consultare questo articolo nel blog di React.

Aggiornare:

A partire da React 16.8 , il useRefgancio può essere utilizzato nei componenti di funzione per ottenere lo stesso risultato:

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

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

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

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

26

Ho appena incontrato questo problema e sto usando reagire 15.0.1 15.0.2 e sto usando la sintassi ES6 e non riusciva a ottenere quello che mi serviva dalle altre risposte dal V.15 sceso settimane fa e alcune delle this.refsproprietà sono stati deprecati e rimossi .

In generale, ciò di cui avevo bisogno era:

  1. Mettere a fuoco il primo elemento di input (campo) quando il componente viene montato
  2. Mettere a fuoco il primo elemento di input (campo) con un errore (dopo l'invio)

Sto usando:

  • Contenitore React / Componente presentazione
  • Redux
  • React-Router

Mettere a fuoco il primo elemento di input

Ho usato autoFocus={true}il primo<input /> sulla pagina in modo che quando il componente si monta, si focalizzerà.

Mettere a fuoco il primo elemento di input con un errore

Ciò ha richiesto più tempo ed è stato più contorto. Sto tenendo fuori il codice che non è rilevante per la soluzione per brevità.

Negozio / Stato Redux

Ho bisogno di uno stato globale per sapere se devo impostare lo stato attivo e disabilitarlo quando è stato impostato, quindi non continuerò a reimpostare lo stato attivo quando i componenti vengono nuovamente sottoposti componentDidUpdate()a rendering (userò per verificare l'impostazione dello stato attivo. )

Questo potrebbe essere progettato come ritieni adatto alla tua applicazione.

{
    form: {
        resetFocus: false,
    }
}

Componente contenitore

Il componente dovrà avere la resetfocusproprietà impostata e un callBack per cancellare la proprietà se finisce per focalizzarsi su se stesso.

Inoltre, ho organizzato i miei creatori di azioni in file separati, principalmente perché il mio progetto è abbastanza grande e volevo suddividerli in blocchi più gestibili.

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

Componente di presentazione

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
}

Panoramica

L'idea generale è che ogni campo del modulo che potrebbe avere un errore ed essere focalizzato deve controllare se stesso e se deve focalizzarsi su se stesso.

C'è una logica aziendale che deve accadere per determinare se il campo dato è il campo giusto su cui focalizzare l'attenzione. Questo non viene visualizzato perché dipenderà dalla singola applicazione.

Quando viene inviato un modulo, quell'evento deve impostare il flag di focus globale resetFocussu true. Quindi, man mano che ogni componente si aggiorna, vedrà che dovrebbe verificare se ottiene lo stato attivo e, in caso affermativo, invia l'evento per ripristinare lo stato attivo in modo che altri elementi non debbano continuare a controllare.

modifica Come nota a margine, avevo la mia logica di business in un file "utility" e ho appena esportato il metodo e l'ho chiamato all'interno di ognishouldfocus() metodo.

Saluti!


25

I documenti di React ora hanno una sezione per questo. 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
Penso che questo sia un buon modo di farlo per questo particolare scenario.
fabio.sussetto,

Non avevo bisogno di autofocusmontare, stavo solo cercando l'elemento per rimanere focalizzato quando si inseriva un valore. Questo ha funzionato perfettamente per quello scenario. (usando la reazione 15)
Matt Parrilla,

13

Questa non è più la risposta migliore. A partire da v0.13, this.refspotrebbe non essere disponibile fino a quando non componentDidMount()viene eseguito AFTER , in alcuni casi dispari.

Aggiungi il autoFocustag al tuo campo di input, come mostrato sopra da FakeRainBrigand.


4
Più <input autofocus>campi non si comporteranno bene
ᆼ ᆺ ᆼ

4
Ovviamente no. Solo un focus per pagina. Se hai più autofocus, dovresti controllare il tuo codice e le tue intenzioni.
GAEfan,

2
La domanda di @ Dave riguardava la messa a fuoco su un <input>rendering dopo
ᆼ ᆺ ᆼ

1
Sull'autofocus, c'è un modo per forzare anche l'apertura della tastiera iOS?
Remi Sture,

1
@RemiSture stesse domande. Qualcuno ha una soluzione a questo problema?
Nam Lê Quý

12

Ref. Il commento di @ Dave sulla risposta di @Dhiraj; un'alternativa consiste nell'utilizzare la funzionalità di callback dell'attributo ref sull'elemento da renderizzare (dopo il rendering di un componente):

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

Ulteriori informazioni


Quando ho provato questo, ho ottenuto:Uncaught TypeError: Cannot read property 'focus' of null
reectrix

1
Devi controllare null il parametro, sarà nullo quando il componente non è montato. Quindi un semplice component && React.findDomNode.... Leggi di più qui: facebook.github.io/react/docs/…
Per Wiklander

12

Questo è il modo corretto, come autofocus. Quando si utilizza callback anziché stringa come valore di riferimento, viene chiamato automaticamente. Hai a disposizione il tuo riferimento che senza la necessità di toccare il DOM usandogetDOMNode

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

2
che dire di una forma controllata?
pixel 67,

@ pixel67 Inoltre. È possibile impostare il riferimento sugli elementi, ma anche sui componenti. Ma devi esserne consapevole quando lavori con esso. Quindi non tenterai di accedere a .value di input, se imposti il ​​riferimento su React.Component, che avvolge l'input html.
Pavel Hasala,

10

Nota che nessuna di queste risposte ha funzionato per me con un componente TextField material-ui . Per Come mettere a fuoco un materialeUI TextField? Ho dovuto saltare attraverso alcuni cerchi per farlo funzionare:

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

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

2
Sembra che se il componente si sta animando, la chiamata a focus()deve essere ritardata fino alla fine dell'animazione.
adriendenat,

9

È possibile inserire quella chiamata del metodo all'interno della funzione di rendering. O all'interno del metodo del ciclo di vita,componentDidUpdate


1
componentDidUpdate è ciò che ha funzionato per il mio caso. Dopo aver chiamato il rendering, dovevo mettere a fuoco un determinato pulsante.
FariaC,

8

Non hai bisogno getInputDOMNode?? in questo caso...

Basta semplicemente ottenere il refe focus()quando il componente viene montato - 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 ha funzionato meglio per me. Avevo bisogno di cambiare del testo in un input con quel testo con un doppio clic, quindi questo è quello che ho finito con:

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

NOTA: per risolvere il problema a causa del quale React posiziona il cursore all'inizio del testo, utilizzare questo metodo:

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

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


3

Ho lo stesso problema ma ho anche qualche animazione, quindi il mio collega suggerisce di usare window.requestAnimationFrame

questo è l'attributo ref del mio elemento:

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

2

Avvertenza: ReactDOMComponent: non accedere a .getDOMNode () di un nodo DOM; utilizzare invece direttamente il nodo. Questo nodo DOM è stato reso da App.

Dovrebbe essere

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

2

La risposta più semplice è aggiungere ref = "some name" nell'elemento di testo di input e chiamare la funzione di seguito.

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

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

2

Per spostare lo stato attivo su un elemento appena creato, è possibile memorizzare l'ID dell'elemento nello stato e utilizzarlo per impostare autoFocus. per esempio

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

In questo modo nessuna delle caselle di testo viene messa a fuoco sul caricamento della pagina (come voglio), ma quando si preme il pulsante "Aggiungi" per creare un nuovo record, quel nuovo record diventa attivo.

Dato autoFocusche non "gira" di nuovo a meno che il componente non venga rimontato, non devo preoccuparmi di disinserire this.state.focus(cioè non continuerò a rubare il focus mentre aggiorno altri stati).


1

Leggi quasi tutte le risposte ma non hai visto a getRenderedComponent().props.input

Imposta i riferimenti per l'inserimento del testo

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


Per favore chiarisci ulteriormente la tua risposta nel contesto del loro codice.
Jimmy Smith,

1

Dopo aver provato molte opzioni sopra senza successo, ho scoperto che era come ero disablinge poienabling l'input che ha causato la perdita di attenzione.

Avevo un oggetto di scena sendingAnswerche disabilitava l'input mentre eseguivo il polling del backend.

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

Una volta rimosso l'elica disabilitata, tutto ha ripreso a funzionare.


0

Versione aggiornata che puoi controllare qui

componentDidMount() {

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

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

0

Poiché ci sono molte ragioni per questo errore, ho pensato che avrei postato anche il problema che stavo affrontando. Per me, il problema era che ho reso i miei input come contenuto di un altro componente.

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

Questo è il modo in cui ho chiamato il componente sopra:

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

0

In base alla sintassi aggiornata, è possibile utilizzare this.myRref.current.focus()

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.