如何为克隆的React元素添加Ref,实现点击容器聚焦输入框?
解决方法:通过
React.cloneElement传递Ref实现容器点击聚焦子Input 这问题我之前做表单组件时也碰到过,其实核心就是给子元素动态添加ref,然后在容器点击时调用聚焦方法就行,咱们一步步来改你的代码:
步骤1:初始化组件内部的Ref
首先在组件的构造函数里创建一个ref,用来保存子input的DOM引用:
constructor(props) { super(props); this.inputRef = React.createRef(); }
步骤2:克隆子元素并传递Ref
你现在是直接渲染this.props.children[0],咱们用React.cloneElement给这个子元素加上ref属性,把刚才创建的inputRef传进去:
React.cloneElement(this.props.children[0], { ref: this.inputRef })
这样就能在组件内部获取到子input的DOM节点了。
步骤3:添加容器点击事件处理函数
写一个点击事件的回调,当容器被点击时,调用input的focus()方法:
handleContainerClick = () => { // 先判断ref是否存在,避免报错 if (this.inputRef.current) { this.inputRef.current.focus(); } }
步骤4:把点击事件绑定到外层容器
给最外层的lone-input-container div加上onClick属性,绑定刚才的处理函数:
<div className="lone-input-container" onClick={this.handleContainerClick}>
完整修改后的组件代码
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Tooltip } from '@material-ui/core'; export class Input extends Component { constructor(props) { super(props); // 初始化ref this.inputRef = React.createRef(); } displayTitle () { if (this.props.tip) { return ( <label htmlFor={this.props.name} className="lone-input-container-title"> {this.props.title} <Tooltip placement="top" arrow title={this.props.tip}> <span className="shadow-md p-1 text-hardbacon rounded-full px-2 cursor-pointer ml-2">?</span> </Tooltip> </label> ); } return ( <label htmlFor={this.props.name} className="lone-input-container-title"> {this.props.title} </label> ); } // 容器点击处理函数 handleContainerClick = () => { if (this.inputRef.current) { this.inputRef.current.focus(); } } render () { return ( <div className="lone-input-container" onClick={this.handleContainerClick}> {this.displayTitle()} <div> {/* 克隆子元素并传递ref */} {React.cloneElement(this.props.children[0], { ref: this.inputRef })} </div> </div> ); } } Input.propTypes = { name: PropTypes.string, title: PropTypes.string.isRequired, children: PropTypes.node.isRequired, tip: PropTypes.string }; export default Input;
额外注意点
- 如果你的子元素不是原生
<input>,而是自定义组件(比如Material-UI的TextField),那这个自定义组件需要支持ref转发(用React.forwardRef包裹),否则ref会指向组件实例而不是内部的input DOM节点。 - 可以在
propTypes里把children的限制更严格,比如PropTypes.element.isRequired,确保传入的是单个元素,避免children[0]出问题。
内容的提问来源于stack exchange,提问作者NicolasSC
相关产品推荐
相关产品推荐

