渲染后如何在输入字段上设置焦点?


628

呈现组件后,将焦点设置在特定文本字段上的反应是什么?

文档似乎建议使用引用,例如:

ref="nameInput"在渲染功能中的输入字段上进行设置,然后调用:

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

但是我应该在哪里称呼它呢?我已经尝试了几个地方,但无法正常工作。

Answers:


668

您应该这样做,componentDidMountrefs callback不是。像这样

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
这是正确的答案,但是它对我不起作用,因为在单击另一个按钮之前,我的组件首先不呈现任何内容。这意味着它已经被挂载了,所以我不得不添加this.refs.nameInput.getDOMNode()。focus();。在componentDidUpdate中而不是componentDidMount中。
戴夫

9
为什么在调用element.focus()时将光标放在输入的开头?我在chrome中的应用程序中实际上在<textarea>中看到了这个(我认为是)错误,现在在这里检查您的演示是一样的。
davnicwil

15
警告:不推荐使用React.findDOMNode。请改为使用require('react-dom')中的ReactDOM.findDOMNode。
安德烈·佩纳

5
@HuwDavies我想您可以使用元素上的ref回调属性来实现<input>。有点像<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
赫尔曼,2016年

5
为什么我们不只使用 ref = {(input)=> {input.focus()}} ?这个解决方案对我来说很好。
HCLiu

840

@Dhiraj的答案是正确的,为方便起见,您可以使用autoFocus道具在安装时让输入自动聚焦:

<input autoFocus name=...

请注意,在jsx中,它autoFocus(大写F)与不区分大小写的普通旧html不同。


95
请注意,在JSX其自动˚F OCUS(大写F)不像普通的旧的HTML是不区分大小写。
prauchfuss 2015年

8
很好,经过漫长的无结果的搜索之后才到达这里:)仅供参考-我最终使用了React.DOM.input({type:'text',defaultValue:content,autoFocus:true,onFocus:function(e){e.target。 select();}})
mlo55 '16

4
我发现autoFocus仅适用于首页渲染。请参阅codepen.io/ericandrewlewis/pen/PbgwqJ?editors=1111,输入应在3秒钟后聚焦。
埃里克·安德鲁·刘易斯

45
此方法+1。值得一提的是autofocus,它不仅使用了HTML5不可靠的属性,而且实际上还用于focus()DOM挂载中,react-dom因此非常可靠。
亚伦·比尔

3
不仅“为了方便”,而且如果您的组件是功能组件,也是如此。
phillyslick

167

从React 0.15开始,最简洁的方法是:

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

5
这也可以处理初始渲染之外的场景,而仅使用autoFocus则不能。
Matt Stannett

问题,什么时候输入错误?我指的是箭头功能内的表达式。
JaeGeeTee

2
@JaeGeeTee在安装组件之前和/或在卸载组件之后为null(我不记得是哪种情况)。
伊利亚·谢梅诺夫

12
与此唯一的问题是,它侧重于输入任何重新渲染这可能是不希望..
雅罗斯拉夫BENC

在我的情况下不起作用(使用Ant Design输入组件)
vsync

117

专注于坐骑

如果只想在挂载(初始渲染)时聚焦某个元素,则只需使用autoFocus属性即可。

<input type="text" autoFocus />

动态焦点

要动态控制焦点,请使用常规功能从组件中隐藏实现细节。

React 16.8 +功能组件-useFocus挂钩

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

完整演示

React 16.3 +类组件-exploitFocus

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

完整演示


2
这个答案包含了React Hooks的正确方法。超!它不是在TypeScript中按原样进行类型检查,而是一种(丑陋的)方式来使其工作:(1)(htmlElRef.current as any).focus()和(2)return {htmlElRef, setFocus}而不是数组。
艾哈迈德·法西

@AhmedFasih,我知道您在说什么,但我认为这超出了本主题的范围。如果返回一个对象,则将更难以控制变量的名称,如果要使用useFocus多个元素,可能会出现问题。
本·卡尔

8

2
多汁,谢谢!!!哇,我不知道const断言(as const您有),非常有教育意义!
艾哈迈德·法西

@BenCarp对于钩子的小建议,最好将其set放在第二个位置const [inputRef, setInputFocus] = useFocus()。这与useState更匹配。首先是对象,然后是该对象的设置者
Rubanov

59

如果您只想在React中进行自动对焦,那很简单。

<input autoFocus type="text" />

如果您只是想知道将代码放在哪里,答案在componentDidMount()中。

v014.3

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

在大多数情况下,您可以将引用附加到DOM节点,而完全避免使用findDOMNode。

在此处阅读API文档:https : //facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode


9
并记住要大写F!(注意自我和他人,而不是回答者)。
2540625

29

React 16.3通过在组件的构造函数中创建一个ref并使用如下所示,添加了一种新的便捷方式来处理此问题:

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

有关更多详细信息,您可以查看本文在React博客中。

更新:

从React 16.8开始,useRef可以在函数组件中使用hook来获得相同的结果:

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

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

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

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

26

我刚遇到这个问题,并且我使用的是React 15.0.1 15.0.2,并且我使用的是ES6语法,但由于v.15在几周前就已删除,因此我并没有从其他答案中得到所需的东西和一些this.refs属性已弃用移除

总的来说,我需要的是:

  1. 安装组件时,集中第一个输入(字段)元素
  2. 将第一个输入(字段)元素聚焦于错误(提交之后)

我在用着:

  • React容器/演示组件
  • Redux
  • 反应路由器

关注第一个输入元素

我在页面autoFocus={true}的第一个<input />上使用过,以便在装入组件时将其聚焦。

使第一个输入元素出现错误

这花费了更长的时间并且更加令人费解。我保留与简洁解决方案无关的代码。

Redux商店/州

我需要一个全局状态来知道是否应该设置焦点并在设置焦点时将其禁用,因此当组件重新渲染时,我不会一直保持焦点设置(我将使用 componentDidUpdate()用来检查设置焦点。 )

可以按照您认为适合自己的应用程序进行设计。

{
    form: {
        resetFocus: false,
    }
}

容器组件

该组件将需要具有 resetfocus最终将焦点放在自身上,设置属性和一个CallBack来清除该属性。

另请注意,由于我的项目相当大,我将动作创建者组织到单独的文件中,并且我想将它们分解为更易于管理的块。

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

演示组件

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
}

总览

通常的想法是,每个可能有错误并被关注的表单域都需要检查自身,以及是否需要将焦点放在自身上。

需要确定业务逻辑来确定给定字段是否是要重点关注的正确字段。由于依赖于各个应用程序,因此未显示。

提交表单时,该事件需要将全局焦点标志设置resetFocus为true。然后,当每个组件更新自身时,它将看到它应该检查以查看是否获得焦点,如果是,则调度该事件以重置焦点,以便其他元素不必继续检查。

编辑 作为一个附带说明,我将业务逻辑保存在“实用程序”文件中,我只是导出了该方法,并在每个shouldfocus()方法中对其进行了调用。

干杯!


25

现在,React文档对此有一个部分。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
我认为这是针对这种特定情况的一种好方法。
fabio.sussetto

我不需要autofocus挂载,只需要寻找输入值时保持焦点的元素即可。在这种情况下,这非常适合。(使用react 15)
Matt Parrilla

13

这不再是最佳答案。从v0.13 this.refs版本开始componentDidMount(),在某些奇怪的情况下,AFTER 运行之前可能不可用。

只需将autoFocus标签添加到您的输入字段中,如上面的FakeRainBrigand所示。


4
多个<input autofocus>字段的表现
不佳

4
当然不是。每页仅一个焦点。如果您有多个自动对焦,则应检查代码和意图。
GAEfan,2015年

2
<input>
@Dave

在自动对焦方面,是否有办法也可以强制打开iOS键盘?
Remi Sture

@RemiSture同样的问题。有谁能解决这个问题?
NamLêQuý19年

12

参考 @Dave对@Dhiraj答案的评论;一种替代方法是在要渲染的元素上使用ref属性的回调功能(在组件首次渲染之后):

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

更多信息


当我尝试这样做时,我得到:Uncaught TypeError: Cannot read property 'focus' of null
reectrix '16

1
您必须对参数进行null检查,当未安装组件时它将为null。如此简单component && React.findDomNode...。:了解更多关于在这里facebook.github.io/react/docs/...
每Wiklander

12

这是自动对焦的正确方法。当使用回调而不是字符串作为参考值时,将自动调用它。您可以获得参考,而不需要使用来接触DOM。getDOMNode

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

2
受控形式呢?
像素

@ pixel67也。您可以在元素上设置引用,也可以在组件上设置引用。但是在使用它时,您必须意识到这一点。因此,如果您在React.Component上设置引用,则不会尝试访问input的.value,它包装了html输入。
帕维尔·哈萨拉

10

请注意,这些答案均不适用于material-ui TextField组件。每如何将焦点设置为materialUI TextField?我必须跳过一些箍才能使它起作用:

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

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

2
好像您的组件正在制作动画,对的调用focus()必须延迟到动画结束。
adriendenat

9

您可以将该方法调用放入render函数中。或在生命周期方法中,componentDidUpdate


1
componentDidUpdate是适用于我的情况的。调用渲染后,我需要将焦点设置在特定按钮上。
FariaC

8

你不需要getInputDOMNode?? 在这种情况下...

只需在安装组件时获取它reffocus()它-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最适合我。我需要双击将某些文本更改为带有该文本的输入,所以最终得到的结果是:

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

注:要解决React将插入号放置在文本开头的问题,请使用以下方法:

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

在这里找到:https : //coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js


3

我有同样的问题,但是我也有一些动画,所以我的同事建议使用window.requestAnimationFrame

这是我元素的ref属性:

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

2

警告:ReactDOMComponent:不要访问DOM节点的.getDOMNode()。而是直接使用该节点。此DOM节点由渲染App

应该

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

2

最简单的答案是在输入文本元素中添加ref =“ some name”并调用以下函数。

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

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

2

要将焦点移到新创建的元素上,可以将元素的ID存储在状态中,并使用它来设置autoFocus。例如

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

这样,所有文本框都不会集中在页面加载上(就像我想要的那样),但是当您按下“添加”按钮来创建新记录时,该新记录就会得到关注。

由于autoFocus除非重新安装该组件,否则它不会再次“运行”,因此我不必费心设置this.state.focus(即在更新其他状态时,它将不会继续窃取焦点)。


1

阅读几乎所有答案,但没有看到 getRenderedComponent().props.input

设置文本输入参考

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


请根据他们的代码进一步阐明您的答案。
吉米·史密斯

1

在尝试了许多以上选项但没有成功之后,我发现它是我原来的样子disabling,然后enabling输入导致焦点丢失。

我有一个道具sendingAnswer,可以在轮询后端时禁用输入。

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

一旦我移除了禁用的道具,一切都会重新开始。


0

更新版本可以在这里查看

componentDidMount() {

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

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

0

由于此错误的原因很多,我认为我也应该发布我所面临的问题。对我来说,问题在于我将输入内容作为另一个组件的内容来呈现。

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

这就是我调用上述组件的方式:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.