react ref with focus() 在没有 setTimeout 的情况下不起作用(我的例子) [英] react ref with focus() doesn't work without setTimeout (my example)

查看:53
本文介绍了react ref with focus() 在没有 setTimeout 的情况下不起作用(我的例子)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到过这个问题,.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

我已经按照这个例子在渲染后对输入设置焦点

渲染功能

render() {const {title, description, tagtext, siteName} = (this.state.selected !== undefined) ?this.state.selected : {};const hasContentChangedYet = this.hasContentChangedYet(title, description);返回 (<div><h2 className={styles.formMainHeader}>编辑元数据表单</h2><table className={styles.formBlock}><tr><td className={styles.tagEditLabel}>标签</td><td className={styles.inputFieldDisableContainer}>{标签文本}</td></tr><tr><td className={styles.tagEditLabel}>地点</td><td className={styles.inputFieldDisableContainer}>{站点名称}</td></tr><tr><td className={styles.tagEditLabel}>标题</td><td className={styles.inputFieldContainer}><反应输入字段参考 =标题输入"id="标题"默认值={(标题)?标题 : ''}onChange={this.onInputChange}占位符=标题"clearTool={true}/></td></tr><tr><td className={styles.tagEditLabel}>描述</td><td className={styles.inputFieldContainer}><反应输入字段id="说明"默认值={(描述)?描述 : ''}onChange={this.onInputChange}占位符=说明"clearTool={true}/></td></tr></tbody><div className={styles.formFooter}><button id="save-button" className={styles.saveButton} disabled={!hasContentChangedYet} onClick={() =>this.handleSavePressed()}>保存<button id="form-cancel-button" className={styles.cancelButton} onClick={this.actions.form.cancelUpdateToTagData}>取消

);}

在看到问题的更新后,我意识到您将深层嵌套的 HTML 传递给 render 函数,并且输入元素在对祖先元素进行 componentDidMount 调用时,您感兴趣的对象确实不可用.如 React v0.13 更改中所述日志:

<块引用>

ref 解析顺序略有变化,因此在调用 componentDidMount 方法后,组件的 ref 立即可用;仅当您的组件在您的 componentDidMount 中调用父组件的回调时,才应观察到此更改,这是一种反模式,无论如何都应避免

这是你的情况.因此,要么您必须将 HTML 结构分解为单独呈现的元素,如此处所述,然后您将在其自己的 componentDidMount 回调中访问 input 元素;或者你只是坚持你拥有的计时器黑客.

使用 componentDidMount 确保代码仅在调用它的组件挂载时运行(请参阅进一步引用的文档).

请注意,不鼓励调用 React.findDOMNode :

<块引用>

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

<块引用>

注意

findDOMNode() 是一个用于访问底层 DOM 节点的逃生舱口.在大多数情况下,不鼓励使用此逃生舱口,因为它刺穿了组件抽象.

findDOMNode() 仅适用于已安装的组件(即已放置在 DOM 中的组件).如果您尝试在尚未安装的组件上调用此方法(例如在尚未创建的组件上调用 render() 中的 findDOMNode())将抛出异常.

来自 ref 字符串属性的文档:><块引用>

  1. render 返回的任何内容分配一个 ref 属性,例如:

     

  2. 在其他一些代码(通常是事件处理程序代码)中,通过 this.refs 访问支持实例,如下所示:

    var input = this.refs.myInput;var inputValue = input.value;var inputRect = input.getBoundingClientRect();

或者,您可以消除对代码的需求,并使用 JSX autoFocus 属性:

I have encounter this problem, the .focus() only works with setTimeout if i take it out and it stop working. can anyone explain me what's the reason for that, possible i am doing it incorrectly and how can i fix the problem.

    componentDidMount() {
        React.findDOMNode(this.refs.titleInput).getElementsByTagName('input')[0].focus();
    }

works example with setTimeout

componentDidMount() {
    setTimeout(() => {
        React.findDOMNode(this.refs.titleInput).getElementsByTagName('input')[0].focus();
    }, 1);
}

JXS

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

and i have followed this example React set focus on input after render

render function

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

解决方案

After seeing the update to the question, I realise that you have deeply nested HTML passed to the render function, and the input element of your interest will indeed not be available at the time of the componentDidMount call on the ancestor element. As stated in the React v0.13 Change Log:

ref resolution order has changed slightly such that a ref to a component is available immediately after its componentDidMount method is called; this change should be observable only if your component calls a parent component's callback within your componentDidMount, which is an anti-pattern and should be avoided regardless

This is your case. So either you have to break down the HTML structure into separately rendered elements, as described here, and then you would access the input element in its own componentDidMount callback; or you just stick with the timer hack you have.

Use of componentDidMount makes sure the code runs only when the component on which it is called is mounted (see quote from docs further down).

Note that calling React.findDOMNode is discouraged:

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

Note

findDOMNode() is an escape hatch used to access the underlying DOM node. In most cases, use of this escape hatch is discouraged because it pierces the component abstraction.

findDOMNode() only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling findDOMNode() in render() on a component that has yet to be created) an exception will be thrown.

And from the docs on the ref string attribute:

  1. Assign a ref attribute to anything returned from render such as:

     <input ref="myInput" />
    

  2. In some other code (typically event handler code), access the backing instance via this.refs as in:

    var input = this.refs.myInput;  
    var inputValue = input.value;  
    var inputRect = input.getBoundingClientRect();  
    

Alternatively, you could eliminate the need of the code, and use the JSX autoFocus attribute:

<ReactInputField
        ref="titleInput"
        autoFocus
        ... />

这篇关于react ref with focus() 在没有 setTimeout 的情况下不起作用(我的例子)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆