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

How to set focus on an input field after rendering?

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

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

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

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

但是我应该在哪里调用呢?我已经尝试了几个地方,但我无法让它工作。

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

您应该在 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>

@Dhiraj 的回答是正确的,为方便起见,您可以使用 autoFocus 属性让输入在挂载时自动对焦:

<input autoFocus name=...

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

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

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

参考。 @Dave 对@Dhiraj 的回答的评论;另一种方法是在正在呈现的元素上使用 ref 属性的回调功能(在组件首次呈现之后):

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

More info

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

<input autoFocus type="text" />

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

v014.3

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

In most cases, you can attach a ref to the DOM node and avoid using findDOMNode at all.

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

Warning: ReactDOMComponent: Do not access .getDOMNode() of a DOM node; instead, use the node directly. This DOM node was rendered by App.

应该是

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

我刚刚 运行 解决了这个问题,我正在使用 react 15.0.1 15.0.2 并且我正在使用 ES6 语法但不太明白自从几周前 v.15 和一些 this.refs properties were deprecated and removed.

下降以来,我需要从其他答案中得到什么

总的来说,我需要的是:

  1. 组件挂载时聚焦第一个输入(字段)元素
  2. 关注第一个输入(字段)元素出现错误(提交后)

我正在使用:

  • React Container/Presentation 组件
  • 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 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。然后,当每个组件更新自身时,它会发现它应该检查自己是否获得焦点,如果获得焦点,则分派事件以重置焦点,这样其他元素就不必继续检查。

编辑 作为旁注,我在 "utilities" 文件中有我的业务逻辑,我只是​​导出方法并在每个 shouldfocus() 方法中调用它。

干杯!

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

这是自动对焦的正确方法。当您使用回调而不是字符串作为 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()}/>

更新版本你可以查看here

componentDidMount() {

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

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

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

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

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

你不需要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'));

请注意,这些答案中的 none 对我有用 material-ui TextField component. Per 我必须克服一些困难才能让它发挥作用:

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

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

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

设置您的文本输入参考

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

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

这是我的元素的 ref 属性:

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

A​​utoFocus 最适合我。我需要在双击时将一些文本更改为带有该文本的输入,所以这就是我最终得到的:

<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 可以在我轮询后端时禁用输入。

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

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

关注坐骑

如果您只想在元素加载(最初呈现)时聚焦元素,只需简单地使用 autoFocus 属性即可。

<input type="text" autoFocus />

动态对焦

要动态控制焦点,请使用通用函数来隐藏组件的实现细节。

React 16.8 + 功能组件 - 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 ] 
}

Full Demo

React 16.3 + Class 组件 - 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} 
}

Full Demo

React 16.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的更多详情,您可以查看this articleReact博客。

更新:

从React16.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>
  );
};

要将焦点移至新创建的元素,您可以将元素的 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>
        )
    }
}

这样 none 的文本框会聚焦于页面加载(就像我想要的那样),但是当您按下 "Add" 按钮创建新记录时,该新记录就会聚焦。

因为 autoFocus 不会再次 "run" 除非组件被重新安装,我不必费心取消设置 this.state.focus (即它不会继续窃取焦点作为我更新其他州)。

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

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

总是先尝试简单和基本的解决方案,适合我。

使用 React Hooks/Functional components with Typescript,你可以使用 useRef hook with 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 hook

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 link。

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