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

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

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

在渲染函数的输入字段上设置ref="nameInput",然后调用:

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

但是我应该把它叫到哪里呢?我试过几个地方,但我不能让它工作。

897282 次浏览

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

你应该用componentDidMountrefs callback代替。像这样

componentDidMount(){this.nameInput.focus();}

class App extends React.Component{componentDidMount(){this.nameInput.focus();}render() {return(<div><inputdefaultValue="Won't focus"/><inputref={(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的答案是正确的,为了方便起见,您可以使用autoFocus道具在挂载时自动对焦输入:

<input autoFocus name=...

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

这不再是最佳答案。从v0.13开始,在一些奇怪的情况下,this.refs可能在componentDidMount()运行后才可用。

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

Ref.@Dave对@Dhiraj的回答的评论;另一种选择是在正在渲染的元素上使用ref属性的回调功能(在组件首次渲染后):

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

更多信息

如果你只是想在React中自动对焦,这很简单。

<input autoFocus type="text" />

而如果你只是想知道把代码放在哪里,答案就在组件迪迪山()中。

v014.3

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

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

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

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

应该是的

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

我刚刚遇到这个问题,我使用的是反应15.0.1 15.0.2,我使用的是ES6语法,自从v.15几周前下降以及一些#0属性已弃用删除以来,我并没有从其他答案中得到我需要的东西。

总的来说,我需要的是:

  1. 当组件挂载时聚焦第一个输入(字段)元素
  2. 聚焦第一个有错误的输入(字段)元素(提交后)

我正在使用:

  • React容器/演示组件
  • Redux
  • 应用路由器开发

聚焦第一个输入元素

我在页面的第一个<input />上使用了autoFocus={true},这样当组件挂载时,它将获得焦点。

用错误聚焦第一个输入元素

这花费了更长的时间并且更加复杂。为了简洁起见,我保留了与解决方案无关的代码。

Redux商店/状态

我需要一个全局状态来知道我是否应该设置焦点并在设置时禁用它,所以当组件重新渲染时,我不会继续重新设置焦点(我将使用componentDidUpdate()来检查设置焦点)。

这可以根据您认为适合您的应用程序进行设计。

{form: {resetFocus: false,}}

容器组件

如果组件最终将焦点设置为自身,则需要设置resetfocus属性和回调以清除属性。

另请注意,我将我的Action Creators组织成单独的文件,主要是因为我的项目相当大,我想将它们分解成更易于管理的块。

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 calledcomponentDidUpdate() {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 focusshouldFocus() {// ...}
// pass the _handleRef callback so we can access// a reference of this element in other component methodsrender() {return (<input ref={this._handleRef} type="text" />);}}
Myfield.propTypes = {clearResetFocus: PropTypes.func,resetFocus: PropTypes.bool}

概览

一般的想法是,每个可能有错误并被聚焦的表单字段都需要检查自己,以及是否需要将焦点设置在自己身上。

需要发生业务逻辑来确定给定字段是否是设置焦点的正确字段。这没有显示,因为它将取决于单个应用程序。

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

编辑作为旁注,我在“实用程序”文件中包含了我的业务逻辑,我只是导出了该方法并在每个shouldfocus()方法中调用它。

干杯!

React文档现在有一个这样的部分。https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute

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

这是正确的方法,如何自动对焦。当您使用回调而不是字符串作为ref值时,它会自动调用。您的ref可用,而无需使用getDOMNode触摸DOM

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

React 0.15,最简洁的方法是:

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

更新的版本,你可以检查这里

componentDidMount() {
// Focus to the input as html5 autofocusthis.inputRef.focus();
}render() {return <input type="text" ref={(input) => { this.inputRef = input }} />})

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

componentDidMount(){this.refs.field_name.focus();}// here field_name is ref name.
<input type="text" ref="field_name" />

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

只需在组件挂载时获取reffocus()-组件类型

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

请注意,这些答案都不适用于我的用户界面TextField组件。根据如何将焦点设置为材料UI文本字段?,我必须跳过一些圈才能使其生效:

const focusUsernameInputField = input => {if (input) {setTimeout(() => {input.focus()}, 100);}};
return (<TextFieldhintText="Username"floatingLabelText="Username"ref={focusUsernameInputField}/>);

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

设置文本输入引用

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

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

这是我的元素的ref属性:

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

自动对焦最适合我。我需要将一些文本更改为双击文本的输入,所以这是我最终得到的:

<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

在尝试了上面的很多选项但没有成功后,我发现这是因为我是disabling,然后是enabling导致焦点丢失的输入。

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

<InputautoFocus={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./>

一旦我删除了禁用的道具,一切又开始工作了。

集中精力坐骑

如果您只想在元素挂载(最初呈现)时聚焦元素,只需使用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+类组件

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

完整的演示

React16.3添加了一种新的便捷方法来处理这个问题,方法是在组件的构造函数中创建一个ref,并像下面这样使用它:

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的更多详细信息,您可以在React博客中查看这篇文章

更新时间:

从React16.8开始,可以在函数组件中使用useRef挂钩来实现相同的结果:

import React, { useEffect, useRef } from 'react';
const MyForm = () => {const textInput = useRef(null);
useEffect(() => {textInput.current.focus();}, []);
return (<div><input ref={textInput} /></div>);};

要将焦点移动到新创建的元素,您可以将元素的ID存储在state中并使用它来设置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(即当我更新其他状态时,它不会继续窃取焦点)。

由于这个错误有很多原因,我想我也会发布我面临的问题。对我来说,问题是我将输入呈现为另一个组件的内容。

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

根据更新后的语法,可以使用this.myRref.current.focus()

<input type="text" autoFocus />

总是先尝试简单和基本的解决方案,为我工作。

使用带有TypeScript的React Hooks/Funcational组件,您可以使用#0钩子HTMLInputElement作为useRef的泛型参数:

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

或者如果使用reactstrap,则将inputReference提供给innerRef而不是ref

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

无需自动对焦的简单解决方案:

<input ref={ref => ref && ref.focus()}onFocus={(e)=>e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length)}/>

ref触发焦点,触发onFocus计算结束并相应地设置光标。

打字稿中的Ben Carp解决方案

React 16.8+功能组件-useFocus钩子

export const useFocus = (): [React.MutableRefObject<HTMLInputElement>, VoidFunction] => {const htmlElRef = React.useRef<HTMLInputElement>(null);const setFocus = React.useCallback(() => {if (htmlElRef.current) htmlElRef.current.focus();}, [htmlElRef]);
return React.useMemo(() => [htmlElRef, setFocus], [htmlElRef, setFocus]);};

专注于为功能组件使用createRef

对于使用功能组件的开发人员。这似乎适合。单击按钮后焦点发生在输入字段上。我也附上了CodeSandbox链接。

import React from 'react';
export default function App() {const inputRef = React.createRef();return <><input ref={inputRef} type={'text'} /><button onClick={() => {if (inputRef.current) { inputRef.current.focus() }}} >Click Here</button></>}

https://codesandbox.io/s/blazing-http-hfwp9t