我遇到了这个问题,.focus()
只适用于setTimeout
,如果我把它拿出来它就会停止工作。任何人都可以解释我的原因是什么,可能我做错了,我该如何解决这个问题。
componentDidMount() {
React.findDOMNode(this.refs.titleInput).getElementsByTagName('input')[0].focus();
}
使用setTimeout
作为示例componentDidMount() {
setTimeout(() => {
React.findDOMNode(this.refs.titleInput).getElementsByTagName('input')[0].focus();
}, 1);
}
JXS
<input ref="titleInput" type="text" />
我已按照此示例React set focus on input after render
渲染功能
render() {
const {title, description, tagtext, siteName} = (this.state.selected !== undefined) ? this.state.selected : {};
const hasContentChangedYet = this.hasContentChangedYet(title, description);
return (
<div>
<h2 className={styles.formMainHeader}>Edit Meta-Data Form</h2>
<table className={styles.formBlock}>
<tbody>
<tr>
<td className={styles.tagEditLabel}>
Tag
</td>
<td className={styles.inputFieldDisableContainer}>
{tagtext}
</td>
</tr>
<tr>
<td className={styles.tagEditLabel}>
Site
</td>
<td className={styles.inputFieldDisableContainer}>
{siteName}
</td>
</tr>
<tr>
<td className={styles.tagEditLabel}>
Title
</td>
<td className={styles.inputFieldContainer}>
<ReactInputField
ref="titleInput"
id="title"
defaultValue={(title) ? title : ''}
onChange={this.onInputChange}
placeholder="Title"
clearTool={true} />
</td>
</tr>
<tr>
<td className={styles.tagEditLabel}>
Description
</td>
<td className={styles.inputFieldContainer}>
<ReactInputField
id="description"
defaultValue={(description) ? description : ''}
onChange={this.onInputChange}
placeholder="Description"
clearTool={true} />
</td>
</tr>
</tbody>
</table>
<div className={styles.formFooter}>
<button id="save-button" className={styles.saveButton} disabled={!hasContentChangedYet} onClick={() => this.handleSavePressed()}>
Save
</button>
<button id="form-cancel-button" className={styles.cancelButton} onClick={this.actions.form.cancelUpdateToTagData}>
Cancel
</button>
</div>
</div>
);
}
答案 0 :(得分:7)
在看到问题的更新后,我意识到你已经将深度嵌套的HTML传递给了 render 函数,并且你感兴趣的输入元素确实无法在< em> componentDidMount 调用祖先元素。如React v0.13 Change Log中所述:
ref
解析顺序略有变化,以便在调用componentDidMount
方法后立即获得对组件的引用;只有当您的组件在componentDidMount
内调用父组件的回调时,才能观察到此更改,这是一种反模式,无论如何都应该避免
这是你的情况。因此,您必须将HTML结构分解为单独呈现的元素,如here所述,然后您将在其自己的 componentDidMount 回调中访问input元素;或者你只是坚持使用计时器黑客。
componentDidMount 的使用确保代码仅在挂载>>的组件 时运行(请参阅文档中的文章) )。
请注意,调用 React.findDOMNode is discouraged:
在大多数情况下,您可以将引用附加到DOM节点,并完全避免使用
findDOMNode
。注意强>
findDOMNode()
是用于访问底层DOM节点的转义符号。在大多数情况下,不鼓励使用此逃生舱,因为它会刺穿组件抽象。
findDOMNode()
仅适用于已安装的组件(即已放置在DOM中的组件)。如果您尝试在尚未挂载的组件上调用此方法(如在findDOMNode()
中调用尚未创建的组件上的render()
),则会抛出异常。
来自ref string attribute上的文档:
为从
ref
返回的任何内容分配render
属性,例如:<input ref="myInput" />
- 醇>
在其他一些代码(通常是事件处理程序代码)中,通过
this.refs
访问支持实例,如下所示:var input = this.refs.myInput; var inputValue = input.value; var inputRect = input.getBoundingClientRect();
或者,您可以省去代码,并使用JSX autoFocus
属性:
<ReactInputField
ref="titleInput"
autoFocus
... />
答案 1 :(得分:1)
使用setTimeout()是个坏主意,而使用componentDidMount()则无关紧要。您可以在以下示例中找到问题的答案:
在父组件中,我呈现一个带有InputText的引言对话框:
<Dialog visible={this.state.visible} ...>
<InputText ref={(nameInp) => {this.nameInp = nameInp}} .../>
...
</Dialog>
最初, this.state.visible 为false,并且对话框是隐藏的。 为了显示对话框,我通过调用showDlg()重新渲染父组件,其中nameInp是对InputText的引用:
showDlg() {
this.setState({visible:true}, ()=>{
this.nameInp.element.focus();
});
}
仅在完成渲染并调用setState回调函数之后,input元素才会获得焦点。
在某些情况下,您可以使用以下方法代替使用setState回调:
componentDidUpdate(){
this.nameInp.element.focus();
}
但是,每次(重新)渲染组件时(包括在InputText隐藏的情况下)都会调用componentDidUpdate()。