Bagaimana cara mengatur fokus pada bidang input setelah rendering?

629

Apa reaksi reaksi pengaturan fokus pada bidang teks tertentu setelah komponen diberikan?

Dokumentasi tampaknya menyarankan penggunaan referensi, misalnya:

Setel ref="nameInput"pada kolom input saya di fungsi render, lalu panggil:

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

Tapi di mana saya harus memanggil ini? Saya sudah mencoba beberapa tempat tetapi saya tidak bisa membuatnya bekerja.

Dave
sumber

Jawaban:

669

Anda harus melakukannya componentDidMountdan refs callbacksebagai gantinya. Sesuatu seperti ini

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
sumber
107
Ini adalah jawaban yang benar, tetapi itu tidak berhasil bagi saya karena komponen saya pertama tidak membuat apa-apa, sampai tombol lain diklik. Ini berarti sudah terpasang, jadi saya harus menambahkan this.refs.nameInput.getDOMNode (). Focus (); di componentDidUpdate, bukan componentDidMount.
Dave
9
Mengapa, ketika element.focus () dipanggil, apakah itu meletakkan kursor di awal input? Saya melihat bug ini (apa yang saya anggap a) di aplikasi saya, di chrome, sebenarnya di <textarea> dan sekarang memeriksa demo Anda di sini sama.
davnicwil
15
Peringatan: React.findDOMNode sudah usang. Harap gunakan ReactDOM.findDOMNode dari require ('react-dom') sebagai gantinya.
André Pena
5
@ HuwDavies Saya kira Anda akan melakukannya menggunakan atribut Callback ref pada <input>elemen. Sesuatu seperti<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
herman
5
Mengapa kita tidak menggunakan ref = {(input) => {input.focus ()}} ? Solusi ini berfungsi dengan baik untuk saya.
HCLiu
841

@Dhiraj's jawaban sudah benar, dan untuk kenyamanan Anda dapat menggunakan prop autoFocus untuk memiliki input secara otomatis fokus ketika dipasang:

<input autoFocus name=...

Perhatikan bahwa dalam jsx itu autoFocus( huruf kapital F) tidak seperti html biasa yang tidak peka huruf besar-kecil.

Perampok
sumber
95
Perhatikan bahwa dalam jsx otomatisnya F ocus (modal F) tidak seperti html biasa yang tidak peka huruf besar-kecil.
prauchfuss
8
Sangat Bagus, Sampai di sini setelah pencarian yang sia-sia :) FYI - Saya akhirnya menggunakan React.DOM.input ({type: 'text', defaultValue: content, autoFocus: true, onFocus: function (e) {e.target. pilih ();}})
mlo55
4
Saya menemukan bahwa autoFocus hanya berfungsi pada render halaman pertama. Lihat codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111 input harus difokuskan setelah 3 detik.
Eric Andrew Lewis
45
+1 untuk metode ini. Perlu disebutkan bahwa ini tidak hanya menggunakan autofocusatribut tidak dapat diandalkan HTML5 , itu benar-benar digunakan focus()pada DOM mountreact-dom sehingga cukup dapat diandalkan.
Aaron Beall
3
Tidak hanya "untuk kenyamanan" tetapi juga jika komponen Anda adalah komponen fungsional.
phillyslick
167

Pada Bereaksi 0,15 , metode yang paling ringkas adalah:

<input ref={input => input && input.focus()}/>
Ilya Semenov
sumber
5
Ini juga menangani skenario di luar render awal sedangkan hanya menggunakan autoFocus tidak.
Matt Stannett
pertanyaan, kapan input salah? Saya mengacu pada ekspresi di dalam fungsi panah.
JaeGeeTee
2
@ JaeGeeTee itu nol sampai komponen sudah terpasang dan / atau setelah itu dilepas (saya tidak ingat pasti yang mana yang terjadi).
Ilya Semenov
12
Satu-satunya masalah dengan ini adalah bahwa ia memfokuskan input pada setiap re-render yang mungkin tidak diinginkan ..
Jaroslav Benc
Tidak berfungsi dalam kasus saya (menggunakan komponen input Desain Ant )
vsync
118

Fokus pada mount

Jika Anda hanya ingin memfokuskan suatu elemen saat ia melakukan mount (awalnya membuat), penggunaan sederhana atribut autoFocus akan dilakukan.

<input type="text" autoFocus />

Fokus dinamis

untuk mengontrol fokus secara dinamis, gunakan fungsi umum untuk menyembunyikan detail implementasi dari komponen Anda.

Bereaksi 16.8 + Komponen fungsional - 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 ] 
}

Demo Penuh

Bereaksi 16.3 + Komponen Kelas - utilFocus

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 Penuh

Ben Carp
sumber
2
Jawaban ini berisi pendekatan yang tepat untuk React Hooks. Super! Itu tidak mengetik centang seperti apa adanya di TypeScript tetapi satu (jelek) cara untuk membuatnya bekerja: (1) (htmlElRef.current as any).focus()dan (2) return {htmlElRef, setFocus}bukan array.
Ahmed Fasih
@AhmedFasih, saya menyadari apa yang Anda katakan, tapi saya pikir itu di luar jangkauan untuk utas ini. Jika Anda mengembalikan objek, itu membuatnya lebih sulit untuk mengontrol nama variabel, yang bisa menjadi masalah jika Anda ingin menggunakan useFocuslebih dari satu elemen.
Ben Carp
8
Di sini useFocusditulis dalam naskah. gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573
Ben Carp
2
Super-juicy, terima kasih !!! Wow, saya tidak tahu tentang pernyataan const (yang as constAnda miliki), sangat mendidik!
Ahmed Fasih
@BenCarp Saran kecil untuk kait, mungkin lebih baik untuk meletakkan setdi posisi kedua seperti const [inputRef, setInputFocus] = useFocus(). Ini cocok menggunakanState lebih. Pertama objek, lalu setter objek itu
Rubanov
59

Jika Anda hanya ingin membuat fokus otomatis di Bereaksi, itu sederhana.

<input autoFocus type="text" />

Sementara jika Anda hanya ingin tahu di mana harus meletakkan kode itu, jawabannya ada di componentDidMount ().

v014.3

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

Dalam kebanyakan kasus, Anda dapat melampirkan referensi ke simpul DOM dan menghindari penggunaan findDOMNode sama sekali.

Baca dokumen API di sini: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode

Jack Lee
sumber
9
Dan ingat untuk memanfaatkan itu F! (Catatan untuk diri sendiri dan orang lain, bukan untuk penjawab).
2540625
29

Bereaksi 16.3 menambahkan cara mudah baru untuk menangani ini dengan membuat referensi dalam konstruktor komponen dan menggunakannya seperti di bawah ini:

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

Untuk lebih jelasnya, Anda dapat memeriksa artikel ini di React blog.

Memperbarui:

Mulai dari React 16.8 , useRefkait dapat digunakan dalam komponen fungsi untuk mencapai hasil yang sama:

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

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

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

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

Saya baru saja mengalami masalah ini dan saya menggunakan react 15.0.1 15.0.2 dan saya menggunakan sintaks ES6 dan tidak mendapatkan apa yang saya butuhkan dari jawaban lain sejak v.15 turun beberapa minggu yang lalu dan beberapa this.refsproperti sudah ditinggalkan dan dihapus .

Secara umum, yang saya butuhkan adalah:

  1. Fokuskan elemen input (bidang) pertama saat komponen dipasang
  2. Fokuskan elemen input (bidang) pertama dengan kesalahan (setelah mengirim)

Saya menggunakan:

  • Bereaksi Wadah / Komponen Presentasi
  • Redux
  • Bereaksi-Router

Fokuskan Elemen Input Pertama

Saya menggunakan autoFocus={true}yang pertama<input /> di halaman sehingga ketika komponen mount, itu akan mendapatkan fokus.

Fokuskan Elemen Input Pertama dengan Kesalahan

Ini memakan waktu lebih lama dan lebih berbelit-belit. Saya menyimpan kode yang tidak relevan dengan solusi untuk singkatnya.

Redux Store / Negara

Saya perlu negara global untuk mengetahui apakah saya harus mengatur fokus dan menonaktifkannya ketika sudah diatur, jadi saya tidak terus mengatur ulang fokus saat komponen dirender ulang (saya akan menggunakan componentDidUpdate() untuk memeriksa pengaturan fokus. )

Ini dapat dirancang sesuai keinginan Anda untuk aplikasi Anda.

{
    form: {
        resetFocus: false,
    }
}

Komponen Wadah

Komponen harus memiliki resetfocus set properti dan callBack untuk menghapus properti jika akhirnya menetapkan fokus pada dirinya sendiri.

Juga perhatikan, saya mengatur Pencipta Tindakan saya ke dalam file terpisah sebagian besar karena proyek saya cukup besar dan saya ingin memecahnya menjadi potongan-potongan yang lebih mudah dikelola.

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

Komponen Presentasi

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
}

Gambaran

Gagasan umum adalah bahwa setiap bidang formulir yang bisa memiliki kesalahan dan menjadi fokus perlu memeriksa sendiri dan jika perlu mengatur fokus pada dirinya sendiri.

Ada logika bisnis yang perlu terjadi untuk menentukan apakah bidang yang diberikan adalah bidang yang tepat untuk menetapkan fokus. Ini tidak ditampilkan karena akan tergantung pada aplikasi individual.

Saat formulir dikirimkan, acara itu perlu mengatur bendera fokus global resetFocusmenjadi true. Kemudian ketika masing-masing komponen memperbarui sendiri, itu akan melihat bahwa itu harus memeriksa untuk melihat apakah itu mendapatkan fokus dan jika ya, mengirimkan acara untuk mengatur ulang fokus sehingga elemen lain tidak harus terus memeriksa.

sunting Sebagai catatan tambahan, saya memiliki logika bisnis saya dalam file "utilitas" dan saya baru saja mengekspor metode dan menyebutnya dalam setiapshouldfocus() metode.

Bersulang!

jmbertucci
sumber
25

Dokumen Bereaksi sekarang memiliki bagian untuk ini. 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
sumber
1
Saya pikir ini adalah cara yang baik untuk melakukannya untuk skenario khusus ini.
fabio.sussetto
Saya tidak perlu autofocusdi mount, hanya mencari elemen untuk tetap fokus ketika memasukkan nilai. Ini bekerja dengan sempurna untuk skenario itu. (menggunakan reaksi 15)
Matt Parrilla
13

Ini bukan lagi jawaban terbaik. Pada v0.13, this.refsmungkin tidak tersedia sampai SETELAH componentDidMount()berjalan, dalam beberapa kasus aneh.

Cukup tambahkan autoFocustag ke bidang input Anda, seperti yang ditampilkan FakeRainBrigand di atas.

GAEfan
sumber
4
Beberapa <input autofocus>bidang tidak akan berperilaku baik
ᆼ ᆺ ᆼ
4
Tentu saja tidak. Hanya satu fokus per halaman. Jika Anda memiliki beberapa fokus otomatis, Anda harus memeriksa kode dan niat Anda.
GAEfan
2
@ Pertanyaan Dave adalah tentang menetapkan fokus pada <input>render setelah
ᆼ ᆺ ᆼ
1
Pada autofocus, apakah ada cara untuk memaksa keyboard iOS juga terbuka?
Remi Sture
1
@ Ingat pertanyaan yang sama. Adakah yang punya solusi untuk masalah ini?
Nam Lê Quý
12

Ref. @ Dave mengomentari jawaban @ Dhiraj; alternatifnya adalah dengan menggunakan fungsi callback dari atribut ref pada elemen yang diberikan (setelah komponen merender terlebih dahulu):

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

Info lebih lanjut

o01
sumber
Ketika saya mencoba ini, saya mendapat:Uncaught TypeError: Cannot read property 'focus' of null
reectrix
1
Anda harus null memeriksa param, itu akan menjadi nol ketika komponen tidak di-mount. Sangat sederhana component && React.findDomNode.... Baca lebih lanjut di sini: facebook.github.io/react/docs/…
Per Wiklander
12

Ini cara yang tepat, cara autofocus. Ketika Anda menggunakan callback alih-alih string sebagai nilai ref, itu secara otomatis dipanggil. Anda mendapatkan referensi Anda tersedia daripada tanpa perlu menyentuh DOM menggunakangetDOMNode

render: function() {
  return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
  this._input.focus();
},
Pavel Hasala
sumber
2
bagaimana dengan bentuk yang dikendalikan?
pixel 67
@ pixel67 Juga. Anda dapat mengatur referensi pada elemen, tetapi juga komponen. Tetapi Anda harus menyadari hal itu ketika bekerja dengannya. Jadi Anda tidak akan mencoba mengakses input nilai, jika Anda menetapkan referensi pada React.Component, yang membungkus input html.
Pavel Hasala
10

Perhatikan bahwa tidak ada jawaban ini yang berfungsi untuk saya dengan komponen TextField material-ui . Per Bagaimana mengatur fokus ke TextUIField materialUI? Saya harus melompati beberapa rintangan agar ini berhasil:

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

return (
  <TextField
    hintText="Username"
    floatingLabelText="Username"
    ref={focusUsernameInputField}
  />
);
Lane Rettig
sumber
2
Sepertinya jika komponen Anda menghidupkan, panggilan focus()ke harus ditunda hingga akhir animasi.
adriendenat
9

Anda dapat menempatkan pemanggilan metode di dalam fungsi render. Atau di dalam metode siklus hidup,componentDidUpdate

Raza Gill
sumber
1
componentDidUpdate adalah yang berfungsi untuk kasus saya. Saya perlu mengatur fokus pada tombol tertentu setelah render dipanggil.
FariaC
8

Kamu tidak perlu getInputDOMNode?? pada kasus ini...

Cukup dengan refdan focus()ketika komponen di-mount - 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
sumber
5

AutoFocus bekerja paling baik untuk saya. Saya perlu mengubah beberapa teks menjadi input dengan teks itu pada klik ganda jadi inilah yang saya akhirnya dapatkan:

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

CATATAN: Untuk memperbaiki masalah di mana Bereaksi menempatkan tanda sisipan di awal teks gunakan metode ini:

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

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

Luke Watts
sumber
3

Saya memiliki masalah yang sama tetapi saya memiliki beberapa animasi juga, jadi kolega saya menyarankan untuk menggunakan window.requestAnimationFrame

ini adalah atribut ref dari elemen saya:

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

Peringatan: ReactDOMComponent: Jangan mengakses .getDOMNode () dari simpul DOM; sebagai gantinya, gunakan node secara langsung. Node DOM ini diberikan oleh App.

Seharusnya

componentDidMount: function () {
  this.refs.nameInput.focus();
}
Kirk Strobeck
sumber
2

Jawaban paling sederhana adalah menambahkan ref = "some name" di elemen teks input dan memanggil fungsi di bawah ini.

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

<input type="text" ref="field_name" />
Venkatesh Somu
sumber
2

Untuk memindahkan fokus ke elemen yang baru dibuat, Anda dapat menyimpan ID elemen dalam keadaan dan menggunakannya untuk mengatur autoFocus. misalnya

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

Dengan cara ini, tidak ada kotak teks yang fokus pada pemuatan halaman (seperti yang saya inginkan), tetapi ketika Anda menekan tombol "Tambah" untuk membuat catatan baru, maka catatan baru itu akan fokus.

Karena autoFocustidak "berjalan" lagi kecuali komponennya di-remount, saya tidak perlu repot-repot untuk tidak menyetel this.state.focus(yaitu tidak akan mencuri kembali fokus ketika saya memperbarui status lainnya).

Mpen
sumber
1

Baca hampir semua jawabannya tetapi tidak melihat getRenderedComponent().props.input

Atur referensi input teks Anda

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

lebih baik
sumber
Silakan lebih jauh mengklarifikasi jawaban Anda dalam konteks kode mereka.
Jimmy Smith
1

Setelah mencoba banyak opsi di atas tanpa hasil, saya menemukan bahwa itu seperti saya disablingdan kemudian enablinginput yang menyebabkan fokus menjadi hilang.

Saya punya prop sendingAnsweryang akan menonaktifkan Input saat saya sedang polling 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.
/>

Setelah saya menghapus prop yang dinonaktifkan semuanya mulai bekerja lagi.

Mendongkrak
sumber
0

Versi yang diperbarui dapat Anda periksa di sini

componentDidMount() {

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

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

Karena ada banyak alasan untuk kesalahan ini, saya berpikir bahwa saya juga akan memposting masalah yang saya hadapi. Bagi saya, masalahnya adalah saya memberikan input sebagai konten dari komponen lain.

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

Ini adalah cara saya menyebut komponen di atas:

<Component Content={() => {
  return (
    <input type="text"/>
  );
}} />
Dean Koštomaj
sumber
0

Menurut sintaks yang diperbarui, Anda dapat menggunakan this.myRref.current.focus()

Arun Kumar
sumber