【发布时间】:2020-11-05 09:59:52
【问题描述】:
在渲染组件后设置焦点在特定文本字段上的反应方式是什么?
文档似乎建议使用 refs,例如:
在渲染函数中我的输入字段设置ref="nameInput",然后调用:
this.refs.nameInput.getInputDOMNode().focus();
但是我应该在哪里称呼它呢?我已经尝试了几个地方,但我无法让它工作。
【问题讨论】:
标签: javascript reactjs
在渲染组件后设置焦点在特定文本字段上的反应方式是什么?
文档似乎建议使用 refs,例如:
在渲染函数中我的输入字段设置ref="nameInput",然后调用:
this.refs.nameInput.getInputDOMNode().focus();
但是我应该在哪里称呼它呢?我已经尝试了几个地方,但我无法让它工作。
【问题讨论】:
标签: javascript reactjs
如果您只想在元素安装(初始渲染)时对其进行聚焦,只需简单地使用 autoFocus 属性即可。
<input type="text" autoFocus />
要动态控制焦点,请使用通用函数来隐藏组件的实现细节。
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 ]
}
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}
}
【讨论】:
(htmlElRef.current as any).focus() 和(2)return {htmlElRef, setFocus} 而不是数组。
useFocus 用于多个元素,这可能会成为问题。
useFocus 用打字稿写的。 gist.github.com/carpben/de968e377cbac0ffbdefe1ab56237573
set 放在第二个位置,如const [inputRef, setInputFocus] = useFocus()。这更匹配 useState。首先是对象,然后是该对象的设置器
打字稿中的 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]);
};
【讨论】:
没有自动对焦的简单解决方案:
<input ref={ref => ref && ref.focus()}
onFocus={(e)=>e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length)}
/>
ref 触发焦点,并触发onFocus 计算结束并相应地设置光标。
【讨论】:
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的更多详细信息,您可以在React博客中查看this article。
更新:
从React 16.8开始,useRef钩子可以用在函数组件中,达到同样的效果:
import React, { useEffect, useRef } from 'react';
const MyForm = () => {
const textInput = useRef(null);
useEffect(() => {
textInput.current.focus();
}, []);
return (
<div>
<input ref={textInput} />
</div>
);
};
【讨论】:
textInput.current?.focus();
使用带有 Typescript 的 React Hooks / 功能组件,您可以使用 useRef hook 和 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 type="text" autoFocus />
总是先尝试简单和基本的解决方案,对我有用。
【讨论】:
根据更新后的语法,可以使用this.myRref.current.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"/>
);
}} />
【讨论】:
要将焦点移至新创建的元素,您可以将元素的 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(即当我更新其他状态时它不会继续抢回焦点)。
【讨论】:
在尝试了上面的很多选项但没有成功后,我发现这是因为我是 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.
/>
一旦我删除了禁用的道具,一切又开始工作了。
【讨论】:
@Dhiraj 的回答是正确的,为方便起见,您可以使用 autoFocus 道具在安装时自动聚焦输入:
<input autoFocus name=...
请注意,在 jsx 中它是 autoFocus(大写 F),这与不区分大小写的普通旧 html 不同。
【讨论】:
autofocus 属性,它实际上是uses focus() on DOM mount in react-dom,所以它是相当可靠的。
你不需要getInputDOMNode??在这种情况下...
当组件被挂载时,只需简单地获取ref 和focus() -- 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'));
【讨论】:
这是正确的方法,如何自动对焦。当您使用回调而不是字符串作为参考值时,它会被自动调用。使用getDOMNode
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._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
【讨论】:
我也有同样的问题,但我也有一些动画,所以我的同事建议使用 window.requestAnimationFrame
这是我的元素的 ref 属性:
ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
【讨论】:
阅读了几乎所有的答案,但没有看到getRenderedComponent().props.input
设置你的文本输入参考
this.refs.username.getRenderedComponent().props.input.onChange('');
【讨论】:
请注意,这些答案都不适用于material-ui TextField component。根据How to set focus to a materialUI TextField?,我不得不跳过一些圈子才能让它工作:
const focusUsernameInputField = input => {
if (input) {
setTimeout(() => {input.focus()}, 100);
}
};
return (
<TextField
hintText="Username"
floatingLabelText="Username"
ref={focusUsernameInputField}
/>
);
【讨论】:
focus()的调用必须延迟到动画结束。
setTimeout(() => {}, 0);只是为了让代码更干净
您应该改为在componentDidMount 和refs 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>
【讨论】:
<input> 元素上使用ref Callback Attribute。类似<input ref={ (component) => ReactDOM.findDOMNode(component).focus() } />
最简单的答案是在输入文本元素中添加 ref="some name" 并调用以下函数。
componentDidMount(){
this.refs.field_name.focus();
}
// here field_name is ref name.
<input type="text" ref="field_name" />
【讨论】:
更新版本可以查看here
componentDidMount() {
// Focus to the input as html5 autofocus
this.inputRef.focus();
}
render() {
return <input type="text" ref={(input) => { this.inputRef = input }} />
})
【讨论】:
从 React 0.15开始,最简洁的方法是:
<input ref={input => input && input.focus()}/>
【讨论】:
我刚刚遇到了这个问题,我正在使用 react 15.0.1 15.0.2 并且我正在使用 ES6 语法,并且从 v 之后的其他答案中并没有完全得到我需要的东西.15 数周前下降,部分 this.refs properties were deprecated 和 removed。
总的来说,我需要的是:
我正在使用:
我在页面上的第一个<input /> 上使用了autoFocus={true},这样当组件挂载时,它就会获得焦点。
这花费了更长的时间并且更加复杂。为了简洁起见,我保留了与解决方案无关的代码。
我需要一个全局状态来知道我是否应该设置焦点并在设置焦点时禁用它,所以当组件重新渲染时我不会继续重新设置焦点(我将使用componentDidUpdate()检查设置焦点。)
这可以按照您认为适合您的应用程序进行设计。
{
form: {
resetFocus: false,
}
}
该组件需要设置resetfocus 属性和一个回调来清除该属性,如果它最终将焦点设置在自身上。
另外请注意,我将我的动作创建者组织成单独的文件,主要是因为我的项目相当大,我想将它们分成更易于管理的块。
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() 方法中调用它。
干杯!
【讨论】:
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();
}
}} />
);
},
【讨论】:
autofocus,只是在寻找输入值时保持焦点的元素。这非常适合这种情况。 (使用反应 15)
警告:ReactDOMComponent:不要访问 DOM 节点的 .getDOMNode();相反,直接使用节点。此 DOM 节点由
App渲染。
应该是
componentDidMount: function () {
this.refs.nameInput.focus();
}
【讨论】:
如果你只是想在 React 中进行自动对焦,这很简单。
<input autoFocus type="text" />
如果您只想知道将代码放在哪里,答案就在 componentDidMount() 中。
v014.3
componentDidMount() {
this.refs.linkInput.focus()
}
在大多数情况下,您可以将 ref 附加到 DOM 节点并完全避免使用 findDOMNode。
在此处阅读 API 文档:https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
【讨论】:
F大写! (注意自己和他人,而不是回答者)。
参考。 @Dave 对 @Dhiraj 回答的评论;另一种方法是在正在渲染的元素上使用 ref 属性的回调功能(在组件首次渲染之后):
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
【讨论】:
Uncaught TypeError: Cannot read property 'focus' of null
component && React.findDomNode...。在此处阅读更多信息:facebook.github.io/react/docs/…
这不再是最佳答案。从 v0.13 开始,在某些奇怪的情况下,this.refs 可能在 componentDidMount() 运行之后才能使用。
只需将 autoFocus 标签添加到您的输入字段,如 FakeRainBrigand 所示。
【讨论】:
<input autofocus> 字段不会很好
<input>
您可以将该方法调用放在渲染函数中。或者生命周期方法里面,componentDidUpdate
【讨论】: