javascript - Render edildikten sonra bir giriş alanına nasıl odaklanılır?
Bileşen render edildikten sonra belirli bir metin alanına odaklanmayı ayarlamanın React yolu nedir?
Belgeler refs kullanmayı önermeye benziyor, örneğin:
Render fonksiyonunda input alanıma ref="nameInput" ayarlayın ve sonra şunu çağırın:
this.refs.nameInput.getInputDOMNode().focus();
Ama bunu nereye çağırmalıyım? Birkaç yer denedim ama çalıştıramadım.
Cevap #1
@Dhiraj'ın cevabı doğru ve rahatlık açısından, bir input bileşeninin monte edildiğinde otomatik olarak odaklanmasını sağlamak için autoFocus özelliğini kullanabilirsiniz:
<input autoFocus name=...
jsx'te bunun autoFocus (büyük F) olduğunu, sıradan html'in ise büyük küçük harfe duyarsız olduğunu unutmayın.
Cevap #2
Bunu bunun yerine componentDidMount ve refs callback içinde yapmalısınız. Şö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>Cevap #3
Dağa odaklan
Sadece bir elemente mount olduğunda (ilk kez render edildiğinde) odaklanmak istiyorsanız, autoFocus özniteliğinin basit bir kullanımı yeterli olacaktır.
<input type="text" autoFocus />
Dinamik odak
Odağı dinamik olarak kontrol etmek için, bileşenlerinizden uygulama ayrıntılarını gizlemek amacıyla genel bir fonksiyon kullanın.
React 16.8 + Fonksiyonel bileşen - useFocus kancası
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
Cevap #4
React 0.15 itibariyle, en kısa yol şudur:
<input ref={input => input && input.focus()}/>
Cevap #5
Sadece React'te otomatik odak yapmak istiyorsanız, bu basittir.
<input autoFocus type="text" />
Eğer sadece bu kodu nereye koymanız gerektiğini merak ediyorsanız, cevap componentDidMount() içinde.
v014.3
componentDidMount() {
this.refs.linkInput.focus()
}
Çoğu durumda, bir ref'i DOM düğümüne ekleyebilir ve findDOMNode kullanmaktan tamamen kaçınabilirsiniz.
API belgelerini burada okuyun: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
Cevap #6
React 16.3, bunu ele almanın yeni ve kullanışlı bir yolunu ekledi; bileşenin yapıcısında bir ref oluşturarak ve aşağıdaki gibi kullanarak:
class MyForm extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current?.focus();
}
render() {
return(
<div>
<input ref={this.textInput} />
</div>
);
}
}
React.createRef hakkında daha fazla detay için React blogundaki bu makaleye göz atabilirsiniz.
Güncelleme:
React 16.8'den itibaren, useRef hook'u işlev bileşenlerinde aynı sonucu elde etmek için kullanılabilir:
import React, { useEffect, useRef } from 'react';
const MyForm = () => {
const textInput = useRef(null);
useEffect(() => {
textInput.current?.focus();
}, []);
return (
<div>
<input ref={textInput} />
</div>
);
};
Cevap #7
React dokümanlarında 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();
}
}} />
);
},
Cevap #8
Az önce bu sorunla karşılaştım ve react 15.0.1 15.0.2 kullanıyorum ve ES6 sözdizimini kullanıyorum ve diğer cevaplardan tam olarak ihtiyacım olanı anlamadım çünkü v.15 haftalar önce çıktı ve bazı this.refs özellikleri kullanımdan kaldırıldı ve kaldırıldı.
Genel olarak, ihtiyacım olan şuydu:
- Bileşen yüklendiğinde ilk giriş (alan) öğesine odaklan
- Hata olan ilk giriş (alan) öğesine odaklan (gönderdikten sonra)
Ben kullanıyorum:
- React Konteyner/Sunum Bileşeni
- Redux
- React-Router
İlk Giriş Öğesine Odaklan
Sayfadaki ilk <input /> üzerinde autoFocus={true} kullandım, böylece bileşen yüklendiğinde odaklanacak.
Hata İçeren İlk Giriş Elemanına Odaklan
Bu daha uzun sürdü ve daha karmaşıktı. Kısalık için çözüme ilişkin olmayan kodu dışarıda bırakıyorum.
Redux Deposu/Durum
Odaklanmayı ayarlayıp ayarlamamam gerektiğini bilmek ve ayarlandığında devre dışı bırakmak için bir global duruma ihtiyacım var, böylece bileşenler yeniden render edildiğinde odaklanmayı tekrar tekrar ayarlamam (odak ayarlamayı kontrol etmek için componentDidUpdate() kullanacağım).
Bu, uygulamanız için uygun gördüğünüz şekilde tasarlanabilir.
{
form: {
resetFocus: false,
}
}
Kapsayıcı Bileşen
Bileşenin resetfocus özelliğine sahip olması ve eğer odak kendisine ayarlanırsa bu özelliği temizlemek için bir geri çağırma (callBack) fonksiyonuna sahip olması gerekecektir.
Ayrıca, Action Creator’larımı ayrı dosyalara düzenlediğimi unutmayın; bunu yapmamın sebebi projemin oldukça büyük olması ve onları daha yönetilebilir parçalara ayırmak istememdi.
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, hata oluşabilecek ve odaklanılabilecek her form alanının kendini kontrol etmesi ve gerekiyorsa kendisine odaklanmayı ayarlamasıdır.
Verilen alanın odağı ayarlamak için doğru alan olup olmadığını belirlemek için yapılması gereken iş mantığı vardır. Bu gösterilmemiştir çünkü bireysel uygulamaya bağlı olacaktır.
Bir form gönderildiğinde, bu olay global odak bayrağını resetFocus true olarak ayarlamalıdır. Daha sonra her bir bileşen kendini güncellediğinde, odaklanıp odaklanmadığını kontrol etmesi gerektiğini görecek ve eğer odaklanıyorsa, diğer öğelerin sürekli kontrol etmesi gerekmediği için odak sıfırlama olayını gönderecektir.
düzenle Bir yan not olarak, iş mantığımı bir "utilities" dosyasında tutuyordum ve sadece yöntemi dışa aktardım ve her bir shouldfocus() yöntemi içinde çağırdım.
Şerefe!
Cevap #9
Bu artık en iyi cevap değil. v0.13 itibariyle, bazı sıra dışı durumlarda this.refs, componentDidMount() çalıştıktan SONRA kullanılamayabilir.
Yukarıda FakeRainBrigand'in gösterdiği gibi, input alanınıza sadece autoFocus etiketini ekleyin.
Cevap #10
Ref. @Dave'in @Dhiraj'ın cevabına yaptığı yorum; bir alternatif, (bir bileşen ilk kez render edildikten sonra) render edilen elementteki ref özniteliğinin geri arama işlevselliğini kullanmaktır:
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
Daha fazla bilgi
Cevap #11
React Hooks/Fonksiyonel bileşenleri TypeScript ile kullanırken, useRef kancasını useRef'in generik parametresi olarak HTMLInputElement ile kullanabilirsiniz:
import React, { useEffect, useRef } from 'react';
export default function MyComponent(): JSX.Element {
const inputReference = useRef<HTMLInputElement>(null);
useEffect(() => {
inputReference.current?.focus();
}, []);
return (
<div>
<input ref={inputReference} />
</div>
);
}
Veya reactstrap kullanıyorsanız, ref yerine innerRef için inputReference sağlayın:
import React, { useEffect, useRef } from 'react';
import { Input } from 'reactstrap';
export default function MyComponent(): JSX.Element {
const inputReference = useRef<HTMLInputElement>(null);
useEffect(() => {
inputReference.current?.focus();
}, []);
return (
<div>
<Input innerRef={inputReference} />
</div>
);
}
Cevap #12
Bu cevapların hiçbiri benim için material-ui TextField bileşeniyle işe yaramadı. MaterialUI TextField'a odaklanmayı ayarlama ile ilgili olarak, bunu çalıştırmak için bazı engelleri aşmam gerekti:
const focusUsernameInputField = input => {
if (input) {
setTimeout(() => {input.focus()}, 100);
}
};
return (
<TextField
hintText="Username"
floatingLabelText="Username"
ref={focusUsernameInputField}
/>
);
Cevap #13
İşte odaklamanın doğru yolu. Ref değeri olarak string yerine callback kullandığınızda, otomatik olarak çağrılır. Böylece, getDOMNode kullanarak DOM'a dokunmanıza gerek kalmadan ref’iniz kullanılabilir hâle gelir.
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._input.focus();
},
Cevap #14
Bu durumda getInputDOMNode'e ihtiyacınız yok...
Sadece ref'i al ve bileşen monte edildiğinde focus() uygula -- 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'));
Cevap #15
Bu benim için işe yaradı:
<input autoFocus={true} />
