Làm cách nào để đặt tiêu điểm vào trường đầu vào sau khi kết xuất?


629

Cách phản ứng của cài đặt tập trung vào một trường văn bản cụ thể sau khi thành phần được hiển thị?

Tài liệu dường như đề xuất sử dụng ref, ví dụ:

Đặt ref="nameInput"trên trường đầu vào của tôi trong chức năng kết xuất, rồi gọi:

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

Nhưng tôi nên gọi nó ở đâu? Tôi đã thử một vài nơi nhưng tôi không thể làm cho nó hoạt động.

Câu trả lời:


669

Bạn nên làm điều đó trong componentDidMountrefs callbackthay vào đó. Một cái gì đó như thế này

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
Đây là câu trả lời đúng, nhưng nó không hoạt động với tôi vì thành phần đầu tiên của tôi không hiển thị gì cả, cho đến khi một nút khác được nhấp. Điều này có nghĩa là nó đã được gắn kết, vì vậy tôi phải thêm this.refs.nameInput.getDOMNode (). Focus (); trong thành phầnDidUpdate thay vì thành phầnDidMount.
Dave

9
Tại sao, khi phần tử.f Focus () được gọi, nó lại đặt con trỏ ở đầu vào? Tôi đã thấy lỗi này (cái mà tôi coi là một) trong ứng dụng của mình, bằng chrome, thực sự là trong <textarea> và bây giờ kiểm tra các bản demo của bạn ở đây cũng giống như vậy.
davnicwil

15
Cảnh báo: React.findDOMNode không được dùng nữa. Vui lòng sử dụng ReactDOM.findDOMNode từ request ('Reac-dom').
André Pena

5
@HuwDavies Tôi đoán bạn sẽ làm điều đó bằng cách sử dụng thuộc tính gọi lại ref trên <input>phần tử. Một cái gì đó giống như<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
herman

5
Tại sao chúng ta không chỉ sử dụng ref = {(input) => {input.f Focus ()}} ? Giải pháp này hoạt động tốt cho tôi.
HCLiu

841

Câu trả lời của @ Dhiraj là chính xác và để thuận tiện, bạn có thể sử dụng prop tự động lấy nét để có đầu vào tự động lấy nét khi được gắn:

<input autoFocus name=...

Lưu ý rằng trong jsx, nó autoFocus(viết hoa F) không giống như html cũ không phân biệt chữ hoa chữ thường.


95
Lưu ý rằng trong jsx, tự động lấy nét F của nó (viết hoa F) không giống như html cũ không phân biệt chữ hoa chữ thường.
Prauchfuss

8
Rất tốt, đã đến đây sau một thời gian dài tìm kiếm không có kết quả :) FYI - Tôi đã kết thúc bằng React.DOM.input ({type: 'text', defaultValue: content, autoF Focus: true, onF Focus: function (e) {e.target. chọn ();}})
mlo55

4
Tôi thấy rằng autoF Focus chỉ hoạt động trên kết xuất trang đầu tiên. Xem codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111 đầu vào nên được tập trung sau 3 giây.
Eric Andrew Lewis

45
+1 cho phương pháp này. Điều đáng nói là nó không chỉ sử dụng autofocusthuộc tính không đáng tin cậy của HTML5 , mà nó thực sự sử dụng focus()trên DOM mountreact-dom vì vậy nó khá đáng tin cậy.
Aaron Beall

3
Không chỉ "để thuận tiện" mà còn nếu thành phần của bạn là một thành phần chức năng.
phillyslick

167

Kể từ React 0.15 , phương pháp ngắn gọn nhất là:

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

5
Điều này cũng xử lý các tình huống bên ngoài kết xuất ban đầu trong khi chỉ sử dụng autoF Focus thì không.
Matt Stannett

Câu hỏi, khi nào đầu vào là sai? Tôi đang đề cập đến biểu thức bên trong hàm mũi tên.
JaeGeeTee

2
@JaeGeeTee không có giá trị cho đến khi thành phần được gắn kết và / hoặc sau khi nó không được kết nối (tôi không nhớ chắc chắn đó là trường hợp nào).
Ilya Semenov

12
Vấn đề duy nhất với điều này là nó tập trung đầu vào vào bất kỳ kết xuất lại nào có thể không mong muốn ..
Jaroslav Benc

Không hoạt động trong trường hợp của tôi (sử dụng thành phần đầu vào Ant Design )
vsync

118

Tập trung vào gắn kết

Nếu bạn chỉ muốn tập trung một phần tử khi nó gắn kết (kết xuất ban đầu), việc sử dụng đơn giản thuộc tính autoF Focus sẽ làm.

<input type="text" autoFocus />

Trọng tâm động

để kiểm soát tập trung một cách linh hoạt sử dụng một chức năng chung để ẩn chi tiết triển khai khỏi các thành phần của bạn.

Phản ứng 16.8 + Thành phần chức năng - useF Focus 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 ] 
}

Bản demo đầy đủ

Phản ứng 16.3 + Các thành phần lớp - tận dụng Lấy nét

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

Bản demo đầy đủ


2
Câu trả lời này chứa cách tiếp cận đúng cho React Hook. Siêu! Nó không đánh máy như trong TypeScript mà là một cách (xấu) để làm cho nó hoạt động: (1) (htmlElRef.current as any).focus()và (2) return {htmlElRef, setFocus}thay vì mảng.
Ahmed Fasih

@AhmedFasih, tôi biết những gì bạn đang nói, nhưng tôi nghĩ nó nằm ngoài phạm vi của chủ đề này. Nếu bạn trả về một đối tượng, việc kiểm soát tên của biến sẽ khó khăn hơn, đây có thể là một vấn đề nếu bạn muốn sử dụng useFocuscho nhiều hơn một phần tử.
Cá chép Ben

8
Ở đây được useFocusviết bằng Bản in. gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573
Cá chép Ben

2
Siêu ngon, cảm ơn bạn !!! Ồ, tôi không biết về các xác nhận const (mà as constbạn có), rất giáo dục!
Ahmed Fasih

@BenCarp Gợi ý nhỏ cho móc, có thể tốt hơn để đặt setở vị trí thứ hai như thế nào const [inputRef, setInputFocus] = useFocus(). Điều này phù hợp với useState hơn. Đầu tiên là đối tượng, sau đó là setter của đối tượng đó
Rubanov

59

Nếu bạn chỉ muốn tự động lấy nét trong React, thật đơn giản.

<input autoFocus type="text" />

Trong khi nếu bạn chỉ muốn biết nơi để đặt mã đó, câu trả lời nằm trong thành phầnDidMount ().

v014.3

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

Trong hầu hết các trường hợp, bạn có thể đính kèm một tham chiếu vào nút DOM và tránh sử dụng findDOMNode.

Đọc tài liệu API tại đây: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode


9
Và nhớ viết hoa đó F! (Lưu ý cho bản thân và những người khác, không trả lời).
2540625

29

React 16.3 đã thêm một cách thuận tiện mới để xử lý việc này bằng cách tạo một ref trong hàm tạo của thành phần và sử dụng nó như dưới đây:

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

Để biết thêm chi tiết, bạn có thể kiểm tra bài viết này trong blog React.

Cập nhật:

Bắt đầu từ React 16.8 , useRefhook có thể được sử dụng trong các thành phần chức năng để đạt được kết quả tương tự:

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

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

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

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

26

Tôi mới gặp phải vấn đề này và tôi đang sử dụng phản ứng 15.0.1 15.0.2 và tôi đang sử dụng cú pháp ES6 và không nhận được những gì tôi cần từ các câu trả lời khác kể từ v.15 đã bỏ cách đây vài tuần và một số this.refsthuộc tính đã bị phản đốiloại bỏ .

Nói chung, điều tôi cần là:

  1. Tập trung phần tử đầu vào (trường) đầu tiên khi thành phần gắn kết
  2. Tập trung phần tử đầu vào (trường) đầu tiên có lỗi (sau khi gửi)

Tôi đang sử dụng:

  • React Container / Thành phần trình bày
  • Redux
  • Bộ định tuyến phản ứng

Tập trung vào yếu tố đầu vào đầu tiên

Tôi đã sử dụng autoFocus={true}đầu tiên<input /> trên trang để khi thành phần gắn kết, nó sẽ lấy nét.

Tập trung phần tử đầu vào đầu tiên có lỗi

Điều này mất nhiều thời gian hơn và phức tạp hơn. Tôi đang giữ mã không liên quan đến giải pháp cho ngắn gọn.

Cửa hàng Redux / Bang

Tôi cần một trạng thái toàn cầu để biết liệu tôi có nên đặt tiêu điểm và tắt nó khi nó được đặt hay không, vì vậy tôi không tiếp tục đặt lại tiêu điểm khi các thành phần kết xuất lại (Tôi sẽ sử dụng componentDidUpdate()để kiểm tra lấy nét. )

Điều này có thể được thiết kế khi bạn thấy phù hợp với ứng dụng của bạn.

{
    form: {
        resetFocus: false,
    }
}

Thành phần container

Thành phần sẽ cần phải có thuộc resetfocustính được thiết lập và một cuộc gọi lại để xóa thuộc tính nếu kết thúc việc thiết lập tập trung vào chính nó.

Cũng lưu ý, tôi đã sắp xếp Trình tạo hành động của mình thành các tệp riêng biệt do dự án của tôi khá lớn và tôi muốn chia chúng thành nhiều phần dễ quản lý hơn.

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

Thành phần trình bày

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
}

Tổng quat

Ý tưởng chung là mỗi trường biểu mẫu có thể có lỗi và được tập trung cần tự kiểm tra và nếu nó cần đặt trọng tâm vào chính nó.

Có logic nghiệp vụ cần phải xảy ra để xác định xem trường đã cho có phải là trường phù hợp để đặt tiêu điểm hay không. Điều này không được hiển thị bởi vì nó sẽ phụ thuộc vào từng ứng dụng.

Khi một biểu mẫu được gửi, sự kiện đó cần đặt cờ tiêu điểm toàn cầu resetFocusthành đúng. Sau đó, khi mỗi thành phần tự cập nhật, nó sẽ thấy rằng nó sẽ kiểm tra xem liệu nó có được lấy nét hay không và nếu có, hãy gửi sự kiện để đặt lại tiêu điểm để các thành phần khác không phải tiếp tục kiểm tra.

chỉnh sửa Như một lưu ý phụ, tôi đã có logic nghiệp vụ của mình trong tệp "tiện ích" và tôi chỉ xuất phương thức và gọi nó trong mỗi tệpshouldfocus() phương thức.

Chúc mừng!


25

Các tài liệu React hiện có một phần cho việc này. https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribution

 render: function() {
  return (
    <TextInput
      ref={function(input) {
        if (input != null) {
          input.focus();
        }
      }} />
    );
  },

1
Tôi nghĩ rằng đây là một cách tốt để làm điều đó cho kịch bản cụ thể này.
fabio.sussetto

Tôi không cần phải autofocusgắn kết, chỉ tìm kiếm yếu tố để duy trì sự tập trung khi nhập một giá trị. Điều này làm việc hoàn hảo cho kịch bản đó. (sử dụng phản ứng 15)
Matt Parrilla

13

Đây không còn là câu trả lời tốt nhất. Kể từ v0.13, this.refscó thể không khả dụng cho đến khi SAU componentDidMount()chạy, trong một số trường hợp lẻ.

Chỉ cần thêm autoFocusthẻ vào trường đầu vào của bạn, như FakeRainBrigand đã hiển thị ở trên.


4
Nhiều <input autofocus>lĩnh vực sẽ không hoạt động tốt
ᆼ ᆺ

4
Dĩ nhiên là không. Chỉ có một tiêu điểm trên mỗi trang. Nếu bạn có nhiều tự động lấy nét, bạn nên kiểm tra mã và ý định của mình.
GAEfan

2
Câu hỏi của @ Dave là về việc tập trung vào <input>kết xuất sau khi kết xuất
ᆼ ᆺ

1
Khi tự động lấy nét, có cách nào để buộc bàn phím iOS cũng mở không?
Remi Sture

1
@RemiSture cùng một câu hỏi. Có ai có một giải pháp nào cho vấn đề này không?
Nam Lê Quý

12

Tham chiếu Nhận xét của @ Dave về câu trả lời của @ Dhiraj; một cách khác là sử dụng chức năng gọi lại của thuộc tính ref trên phần tử được hiển thị (sau khi một thành phần được hiển thị lần đầu tiên):

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

Thêm thông tin


Khi tôi thử nó, tôi nhận được:Uncaught TypeError: Cannot read property 'focus' of null
reectrix

1
Bạn phải null kiểm tra param, nó sẽ là null khi thành phần không được gắn kết. Thật đơn giản component && React.findDomNode.... Đọc thêm về nó ở đây: facebook.github.io/react/docs/ từ
Per Wiklander

12

Đây là cách thích hợp, làm thế nào để tự động lấy nét. Khi bạn sử dụng gọi lại thay vì chuỗi làm giá trị ref, nó sẽ tự động được gọi. Bạn đã có sẵn tài liệu tham khảo của mình hơn mà không cần phải chạm vào DOM bằng cách sử dụnggetDOMNode

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

2
một hình thức kiểm soát thì sao?
pixel 67

@ pixel67 Ngoài ra. Bạn có thể đặt tham chiếu trên các phần tử, nhưng cũng có các thành phần. Nhưng bạn phải nhận thức được điều đó khi làm việc với nó. Vì vậy, bạn sẽ không thử truy cập .value của đầu vào, nếu bạn đặt tham chiếu trên React.Component, nó bao bọc đầu vào html.
Pavel Hasala

10

Lưu ý rằng không có câu trả lời nào trong số này có hiệu quả với tôi với thành phần TextField . Per Làm thế nào để đặt tiêu điểm cho TextField vật liệu? Tôi đã phải nhảy qua một số vòng để làm việc này:

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

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

2
Có vẻ như nếu thành phần của bạn đang hoạt hình, cuộc gọi phải focus()bị trì hoãn cho đến khi kết thúc hoạt hình.
adriendenat

9

Bạn có thể đặt cuộc gọi phương thức đó bên trong chức năng kết xuất. Hoặc bên trong phương pháp vòng đời,componentDidUpdate


1
thành phầnDidUpdate là những gì làm việc cho trường hợp của tôi. Tôi cần phải đặt tiêu điểm vào một nút cụ thể sau khi kết xuất được gọi.
FariaC

8

Bạn không cần getInputDOMNode?? trong trường hợp này...

Chỉ cần lấy reffocus()nó khi thành phần được gắn kết - thành phầnDidMount ...

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

Tự động lấy nét làm việc tốt nhất cho tôi. Tôi cần thay đổi một số văn bản thành một đầu vào với văn bản đó khi nhấp đúp để đây là kết quả mà tôi đã kết thúc:

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

LƯU Ý: Để khắc phục sự cố trong đó React đặt dấu mũ ở đầu văn bản, sử dụng phương pháp này:

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

Tìm thấy ở đây: https://coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js


3

Tôi có cùng một vấn đề nhưng tôi cũng có một số hình ảnh động, vì vậy đồng nghiệp của tôi đề nghị sử dụng window.requestAnimationFrame

đây là thuộc tính ref của phần tử của tôi:

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

2

Cảnh báo: ReactDOMComponent: Không truy cập .getDOMNode () của nút DOM; thay vào đó, sử dụng nút trực tiếp. Nút DOM này được kết xuất bởi App.

Nên là

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

2

Câu trả lời đơn giản nhất là thêm ref = "some name" trong phần tử văn bản đầu vào và gọi hàm bên dưới.

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

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

2

Để di chuyển tiêu điểm đến một phần tử mới được tạo, bạn có thể lưu ID của phần tử ở trạng thái và sử dụng nó để đặt autoFocus. ví dụ

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

Bằng cách này, không có hộp văn bản nào tập trung vào tải trang (như tôi muốn), nhưng khi bạn nhấn nút "Thêm" để tạo bản ghi mới, thì bản ghi mới đó sẽ được lấy nét.

autoFocuskhông "chạy" lại trừ khi thành phần được kết nối lại, tôi không phải bận tâm về việc không cài đặt this.state.focus(tức là nó sẽ không tiếp tục lấy cắp trọng tâm khi tôi cập nhật các trạng thái khác).


1

Đọc gần như tất cả các câu trả lời nhưng không thấy getRenderedComponent().props.input

Đặt refs nhập văn bản của bạn

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


Vui lòng làm rõ hơn câu trả lời của bạn trong bối cảnh mã của họ.
Jimmy Smith

1

Sau khi thử rất nhiều tùy chọn ở trên mà không thành công, tôi thấy rằng nó giống như tôi disablingvà sau đó enablinglà đầu vào khiến cho tiêu điểm bị mất.

Tôi đã có một chỗ sendingAnswerdựa để vô hiệu hóa Đầu vào trong khi tôi đang bỏ phiếu phụ trợ.

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

Khi tôi gỡ bỏ chỗ dựa bị vô hiệu hóa, mọi thứ bắt đầu hoạt động trở lại.


0

Phiên bản cập nhật bạn có thể kiểm tra tại đây

componentDidMount() {

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

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

0

Vì có rất nhiều lý do cho lỗi này, tôi nghĩ rằng tôi cũng sẽ đăng vấn đề mà tôi đang gặp phải. Đối với tôi, vấn đề là tôi đã đưa ra đầu vào của mình dưới dạng nội dung của một thành phần khác.

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

Đây là cách tôi gọi là thành phần trên:

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

0

Theo cú pháp cập nhật, bạn có thể sử dụng this.myRref.current.focus()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.