Oluşturduktan sonra bir girdi alanına odak nasıl ayarlanır?


629

Bileşen oluşturulduktan sonra belirli bir metin alanına odaklanmanın tepki yolu nedir?

Belgeler, ref'lerin kullanılmasını öneriyor gibi görünüyor, örneğin:

ref="nameInput"Oluşturma işlevindeki girdi alanıma ayarlayın ve sonra arayın:

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

Ama bunu nereye çağırmalıyım? Birkaç yer denedim ama işe yarayamıyorum.

Yanıtlar:


668

Sen bunu yapması gerektiğini componentDidMountve refs callbackbunun yerine. Böyle bir şey

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
Bu doğru cevap, ama benim için işe yaramadı çünkü bileşenim başka bir düğme tıklanıncaya kadar hiçbir şey yapmıyor. Bu zaten bağlanmış olduğu anlamına geliyordu, bu yüzden this.refs.nameInput.getDOMNode (). Focus (); componentDidMount yerine componentDidUpdate içinde.
Dave

9
Element.focus () çağrıldığında neden imleci girişin başına koyuyor? Uygulamamda, kromda (aslında bir <textarea>) bu (düşündüğüm şey) bir hatayı gördüm ve şimdi demolarınızı burada kontrol ediyoruz.
davnicwil

15
Uyarı: React.findDOMNode kullanımdan kaldırıldı. Lütfen bunun yerine reactDOM.findDOMNode öğesini koşuldan ('tepki-dom') kullanın.
André Pena

5
@HuwDavies Sanırım bunu öğe üzerinde bir ref Geri Arama Özelliği kullanarak yaparsınız <input>. Gibi bir şey<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
Herman

5
Neden sadece ref = {(input) => {input.focus ()}} kullanmıyoruz ? Bu çözüm benim için iyi çalışıyor.
HCLiu

841

@ Dhiraj'ın cevabı doğrudur ve kolaylık olması açısından, bir girişin monte edildiğinde otomatik olarak odaklanması için autoFocus pervanesini kullanabilirsiniz:

<input autoFocus name=...

Jsx'de autoFocusbüyük / küçük harf duyarsız olan eski html'den farklı olduğunu unutmayın .


95
Jsx'de, büyük / küçük harf duyarsız olan düz eski html'den farklı olarak otomatik F ocus'un (büyük harf F) olduğuna dikkat edin.
prauchfuss

8
Çok İyi, Uzun bir meyvesiz aramadan sonra buraya geldim :) FYI - React.DOM.input ({type: 'text', defaultValue: content, autoFocus: true, onFocus: function (e) {e.target. select ();}})
mlo55 20:06

4
AutoFocus'un yalnızca ilk sayfa görüntülemede çalıştığını görüyorum. Bkz. Codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111 Giriş 3 saniye sonra odaklanmalıdır.
Eric Andrew Lewis

45
Bu yöntem için +1. Bu sadece HTML5 güvenilmez kullanmaz söz It değerinde autofocusniteliğini, aslında kullandığı focus()monte DOM üzerindereact-dom oldukça güvenilir yüzden.
Aaron Beall

3
Sadece "kolaylık sağlamak" için değil, aynı zamanda bileşeniniz işlevsel bir bileşense.
phillyslick

167

React 0.15 itibariyle en kısa yöntem şudur:

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

5
Bu aynı zamanda ilk render dışındaki senaryoları da ele alırken sadece autoFocus'u kullanmaz.
Matt Stannett

soru, girdi ne zaman yanlış olur? Ok fonksiyonunun içindeki ifadeye atıfta bulunuyorum.
JaeGeeTee

2
@JaeGeeBir bileşen monte edilinceye kadar ve / veya bağlantısı kesildikten sonra boş kalır (durumun hangisi olduğundan emin değilim).
Ilya Semenov

12
Bununla ilgili tek sorun, istenilemeyecek herhangi bir yeniden oluşturma girdisine odaklanmasıdır ..
Jaroslav Benc

Benim durumumda çalışmıyor ( Ant Tasarım giriş bileşenini kullanarak )
vsync

118

Bağlamaya odaklan

Bir öğeyi yalnızca monte edildiğinde (başlangıçta oluştururken) odaklamak istiyorsanız, autoFocus özniteliğinin basit bir kullanımı yapılır.

<input type="text" autoFocus />

Dinamik odak

odağı dinamik olarak kontrol etmek için uygulama ayrıntılarını bileşenlerinizden gizlemek için genel bir işlev kullanın.

React 16.8 + Fonksiyonel bileşen - 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 ] 
}

Tam Demo

React 16.3 + Sınıf Bileşenleri - utilizeFocus

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

Tam Demo


2
Bu cevap Tepki Kancaları için doğru yaklaşımı içerir. Süper! TypeScript'te olduğu gibi kontrol etmez, ancak çalışmasını sağlamanın bir (çirkin) yolu vardır: dizi yerine (1) (htmlElRef.current as any).focus()ve (2) return {htmlElRef, setFocus}.
Ahmed Fasih

@AhmedFasih, ne söylediğinin farkındayım, ama bu konu için kapsam dışında olduğunu düşünüyorum. Bir nesneyi döndürürseniz, değişkenin adını kontrol etmeyi zorlaştırır; bu, useFocusbirden fazla öğe için kullanmak istiyorsanız bir sorun olabilir .
Ben Carp

8
İşte useFocusdaktiloda yazılmıştır. gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573
Ben Carp

2
Süper sulu, teşekkür ederim !!! Vay canına, (sahip as constolduğun) const iddialarını bilmiyordum , çok eğitici!
Ahmed Fasih

@BenCarp Kancalar için küçük öneri set, ikinci pozisyona koymak daha iyi olabilirconst [inputRef, setInputFocus] = useFocus() . Bu, useState more ile eşleşir. Önce nesne, sonra o nesnenin ayarlayıcısı
Rubanov

59

React'te otomatik odaklama yapmak istiyorsanız, basit.

<input autoFocus type="text" />

Bu kodu nereye koyacağınızı bilmek istiyorsanız, yanıt componentDidMount () 'dadır.

v014.3

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

Çoğu durumda, DOM düğümüne bir ref ekleyebilir ve findDOMNode kullanmaktan kaçınabilirsiniz.

API belgelerini buradan okuyun: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode


9
Ve bunu büyük harfle yazmayı unutmayın F! (Kendine ve başkalarına not verin, cevap verene değil).
2540625

29

React 16.3 , bileşen yapıcısında bir ref oluşturarak ve bunu aşağıdaki gibi kullanarak yeni bir kullanışlı yol ekledi:

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

Daha fazla ayrıntı için bu makaleyi kontrol edebilirsiniz React blogunda .

Güncelleme:

React 16.8'den başlayarak , useRefkanca, aynı sonucu elde etmek için fonksiyon bileşenlerinde kullanılabilir:

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

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

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

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

26

Ben sadece bu sorunla karşılaştı ve tepki 15.0.1 15.0.2 kullanıyorum ve ES6 sözdizimi kullanıyorum ve v.15 hafta önce ve bazı this.refsözellikleri düştüğünden beri diğer cevaplardan gerekenleri tam olarak alamadım kullanımdan kaldırıldı ve kaldırıldı .

Genel olarak, ihtiyacım olan şey:

  1. Bileşen monte edildiğinde ilk giriş (alan) öğesine odaklanın
  2. İlk giriş (alan) öğesini bir hata ile odaklayın (gönderdikten sonra)

Kullanıyorum:

  • Reaksiyon Kabı / Sunum Bileşeni
  • Redux
  • Tepki-Yönlendirici

İlk Giriş Öğesine Odaklanma

Sayfada autoFocus={true}ilkinde kullandım , <input />böylece bileşen monte edildiğinde odaklanacaktır.

İlk Giriş Öğesini Hata ile Odaklayın

Bu daha uzun sürdü ve daha kıvrımlıydı. Kısalık için çözüm ile ilgili olmayan kodu dışarıda tutuyorum.

Redux Mağazası / Eyalet

Odaklamayı ayarlayıp ayarlamam gerektiğini bilmek için küresel bir duruma ihtiyacım var, bu yüzden bileşenler yeniden oluşturulduğunda odağı yeniden ayarlamaya devam etmiyorum (kullanacağım componentDidUpdate() odak ayarını kontrol etmek için . )

Bu uygulama için uygun gördüğünüz gibi tasarlanabilir.

{
    form: {
        resetFocus: false,
    }
}

Kapsayıcı Bileşeni

Bileşenin aşağıdakilere sahip olması gerekir: resetfocus özelliğin ayarlanmış özelliğin kendisinin ayarını ayarlaması durumunda özelliği temizlemek için bir callBack'e sahip olması gerekir.

Ayrıca, Eylem Yaratıcılarımı çoğunlukla projem oldukça büyük olduğu için ayrı dosyalar halinde düzenledim ve onları daha yönetilebilir parçalar haline getirmek istedim.

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

Sunum Bileşeni

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
}

genel bakış

Genel fikir, bir hataya ve odaklanabilecek her form alanının kendini kontrol etmesi ve kendisine odaklanması gerekip gerekmediğidir.

Verilen alanın odağı ayarlamak için doğru alan olup olmadığını belirlemek için gerçekleşmesi gereken iş mantığı vardır. Tek tek uygulamaya bağlı olacağı için bu gösterilmez.

Bir form gönderildiğinde, o etkinliğin genel odak bayrağını resetFocustrue olarak ayarlaması gerekir . Daha sonra her bileşen kendini güncellediğinde, odağı alıp almadığını kontrol etmeli ve eğer öyleyse, odağı sıfırlamak için olayı göndererek diğer öğelerin denetlemeye devam etmesine gerek kalmayacaktır.

düzenlemek Bir yan not olarak, benim iş mantığı bir "yarar" dosya vardı ve ben sadece yöntemi ihraç ve her içinde denirshouldfocus() yöntem .

Şerefe!


25

React belgelerinde artık bunun için bir bölüm var. 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
Bu özel senaryo için bunu yapmanın iyi bir yolu olduğunu düşünüyorum.
fabio.sussetto

autofocusBağlanmaya ihtiyacım yoktu , sadece bir değer girerken odaklanmayı sürdürecek öğeyi arıyordum. Bu senaryo için mükemmel çalıştı. (tepki 15'i kullanarak)
Matt Parrilla

13

Bu artık en iyi cevap değil. V0.13 itibariyle, bazı garip durumlarda this.refsSONRA çalışana kadar kullanılamayabilir componentDidMount().

autoFocusEtiketi giriş alanınıza eklemeniz yeterlidir, FakeRainBrigand yukarıda gösterildiği gibi.


4
Birden fazla <input autofocus>alan hoş davranmayacak
ᆼ ᆺ ᆼ

4
Tabii ki değil. Sayfa başına yalnızca bir odak. Birden fazla otomatik odaklamanız varsa, kodunuzu ve niyetlerinizi kontrol etmelisiniz.
GAEfan

2
@ Dave'in sorusu bir <input>render işleminden sonra odaklanmakla
ilgiliydi

1
Otomatik odaklamada, iOS klavyesini de açmaya zorlamanın bir yolu var mı?
Remi Sture

1
@RemiSture aynı soruları. Herkes bu soruna bir çözümü var mı?
Nam Lê Quý

12

Ref. @ Dave'in @ Dhiraj'ın cevabı hakkındaki yorumu; bir alternatif, oluşturulmuş öğede (bir bileşen ilk oluşturulduktan sonra) ref özelliğinin geri arama işlevini kullanmaktır:

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

Daha fazla bilgi


Bunu denediğimde, aldım:Uncaught TypeError: Cannot read property 'focus' of null
16:35 reectrix

1
Parametreyi null olarak kontrol etmeniz gerekir, bileşen monte edilmediğinde null olur. Çok basit component && React.findDomNode.... Burada daha fazla bilgi bulabilirsiniz: facebook.github.io/react/docs/…
Wiklander başına

12

Bu, otomatik odaklamanın doğru yoludur. Ref değeri olarak dize yerine geri arama kullandığınızda otomatik olarak çağrılır. Ref kullanarak DOM dokunmadan gerek yokgetDOMNode

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

2
Kontrollü bir form ne olacak?
piksel 67

@ pixel67 Ayrıca. Öğelere değil, bileşenlere de referans ayarlayabilirsiniz. Ama bununla çalışırken bunun farkında olmalısınız. Eğer React.Component üzerinde referans ayarlarsanız, html girişini saran girdinin .value değerine erişmeye çalışmazsınız.
Pavel Hasala

10

Bu yanıtların hiçbirinin benim için bir material-ui TextField bileşeniyle çalışmadığını unutmayın . Per bir materialUI TextField için nasıl ayarlanır? Bunu işe almak için bazı çemberler atlamak zorunda kaldı:

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

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

2
Bileşeniniz animasyonluysa, aramanın focus()animasyonun sonuna kadar ertelenmesi gerekir.
adriendenat

9

Bu yöntem çağrısını oluşturma işlevinin içine koyabilirsiniz. Ya da yaşam döngüsü yönteminin içinde,componentDidUpdate


1
componentDidUpdate benim durumum için çalıştı. Oluşturma çağrıldıktan sonra odağı belirli bir düğmeye ayarlamam gerekiyordu.
FariaC

8

İhtiyacınız yok getInputDOMNode?? bu durumda...

Bileşen monte edildiğinde sadece refve focus()alın - 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 benim için en iyi sonucu verdi. Ben ile sona erdi bu yüzden çift tıklama üzerinde o metin ile bir giriş bazı metin değiştirmek gerekiyordu:

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

Not: React metnin başlangıcına düzeltme işareti yerleştirme sorunu gidermek için şu yöntemi kullanın:

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

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


3

Aynı sorunum var ama ben de bazı animasyon var, bu yüzden meslektaşım window.requestAnimationFrame kullanmanızı öneririm

bu benim öğenin ref özniteliğidir:

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

2

Uyarı: ReactDOMComponent: Bir DOM düğümünün .getDOMNode () öğesine erişmeyin; bunun yerine, düğümü doğrudan kullanın. Bu DOM düğümü tarafından oluşturuldu App.

Olmalı

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

2

En basit cevap, giriş metni öğesine ref = "bir isim" eklemek ve aşağıdaki işlevi çağırmaktır.

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

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

2

Odağı yeni oluşturulan bir öğeye taşımak için öğenin kimliğini durumda saklayabilir ve ayarlamak için kullanabilirsiniz autoFocus. Örneğin

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

Bu şekilde metin kutularının hiçbiri sayfa yüklemesine odaklanamaz (istediğim gibi), ancak yeni bir kayıt oluşturmak için "Ekle" düğmesine bastığınızda yeni kayıt odaklanır.

Dan beri autoFocus değil bileşen remounted verilmezse "run" yine, unsetting zahmet gerekmez this.state.focus(ı diğer durumlarını düzelterek olarak yani o odak geri çalmak tutmaz).


1

Hemen hemen tüm cevabı oku ama görmedim getRenderedComponent().props.input

Metin girişi referanslarınızı ayarlama

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


Lütfen yanıtınızı kodları bağlamında daha ayrıntılı olarak açıklayın.
Jimmy Smith

1

Yukarıdaki bir çok seçeneği denedikten sonra hiçbir başarı ile denedim disablingsonra ben olduğumu ve sonra enablingodak kaybına neden girdi olduğunu gördüm .

Ben sendingAnswerarka uç yoklama sırasında Giriş devre dışı bırakacak bir pervane vardı .

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

Engelli pervane kaldırıldıktan sonra her şey tekrar çalışmaya başladı.


0

Buradan kontrol edebileceğiniz güncellenmiş sürüm

componentDidMount() {

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

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

0

Bu hatanın birçok nedeni olduğundan, karşılaştığım sorunu da yayınlayacağımı düşündüm. Benim için sorun, girdilerimi başka bir bileşenin içeriği olarak oluşturmamdı.

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

Ben yukarıdaki bileşen bu şekilde aradı:

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

0

Güncellenmiş sözdizimine göre şunları kullanabilirsiniz: this.myRref.current.focus()

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.