ref
ref属性可以帮助我们获取子组件的实例或者DOM对象,进而对子组件进行修改。
使用场景: 希望直接使用dom元素中的某个方法,或者希望直接使用自定义组件中的某个方法。
ref的注意事项
-
ref作用域内置的html组件,得到的将是真实的dom对象
-
ref作用域类组件,得到的将是类的实例
-
ref不能直接作用于函数组件,但是可以使用ref转发和HOOK使用ref
不论是在函数里面使用,还是使用函数组件的标签,都不可以使用ref
function CompB(props) { function handleFunClick() { console.log('CompB', props); } return ( <> <h1 refs="h1">我是函数组件B</h1> <button onClick={handleFunClick}>函数组件CompB</button> </> ) } render() { return ( <> <CompB ref="CompB" /> </> ); } 复制代码
ref的写法
-
字符串式写法(不被推荐使用)
由于效率问题被不推荐,并且不灵活
<input ref="text" type="text" />
<CompA ref="CompA" />
复制代码
调用:
this.refs.text
复制代码
-
对象使写法
React.createRef()
React.createRef()会创建一个对象,在这个对象里面有一个current属性,用来保存DOM元素或者实例对象。这时输出的所创建对象得到的DOM元素对象或者实例中的refs中的值是空
每创建一个,如:this.text 只能控制一个DOM元素或者实例对象,这是由于 current 没有被设计成对象 / 数组无法保存多个DOM元素或实例对象
React.createRef() 在render的时候赋值,遇到了jsx对象中有使用 React.createRef() 的就会进行赋值
class NewRef extends Component {
constructor(props) {
super(props);
this.text = React.createRef();
this.text = {// 可以自己写一个 createRef() 函数,这就是其返回值
current: null
};
console.log(this.text);
}
handleFocus= () => {
console.log(this);
this.text.current.focus();
}
render() {
return (
<>
<input ref={this.text} type="text" />
<input ref={this.text} type="text" />
<input ref={this.text} type="text" />
<input ref={this.text} type="text" />
<p ref={this.text}>123123</p>
<button onClick={this.handleFocus}>聚焦</button>
</>
);
}
}
复制代码
-
函数形式写法
函数式写法就是在React元素或者组件上面直接添加一个函数,这时输出的所创建对象得到的DOM元素对象或者实例中的refs中的值是空。
<input ref={el => {
this.text = el;
console.log('查看el的状态', el);
}} type="text" />
复制代码
函数中的参数(el) 代表的是DOM对象或者实例,react自动会传入的一个,无需自己传入;this.text 就是ref 的名字。
渲染调用
如果在元素的行内式中加上函数,那么在渲染之后会重复调用两次。
class FunRef extends Component {
handleFocus = () => {
this.text.focus();
this.setState({})
}
render() {
return (
<div>
<input ref={el => {
this.text = el;
console.log('查看el的状态', el);
}} type="text" />
{/* <input ref={el => {
this.text = el;
console.log('查看el的状态', el);
}} type="text" /> */}
<button onClick={this.handleFocus}>点击聚焦</button>
</div>
);
}
}
复制代码
每当点击按钮聚焦的时候,使用setState会引起render重新渲染,导致行内式函数会调用两次,第一次输出的el的值是null,第二次输出的值是ref绑定的值。并且在页面加载之后就会发生一次调用ref函数。
这样就会导致,ref函数无法跟踪到值的改变,当时可以进行一些与值无关的操作。这样每次执行render就会重新调用一次函数,函数的值一直都是原来的值,已发生改变就会调用一个新的函数,那么怎么做可以改变这一现象呢?
其实只要在render外部调用这个函数即可,这样每次render调用的函数只会是这个外部的函数,函数的引用地址不会发生改变,并且外部函数的引用没有发生任何变化,所以函数也不会重复的执行。这样无论如何点击,都不会输出,因为在页面加载的时候已经调用过了这个函数。
class FunRef extends Component {
handleFocus = () => {
// console.log(this);
this.text.focus();
this.setState({})
}
handleRefFun = el => {
this.text = el;
console.log('查看el的状态', el);
}
render() {
return (
<div>
<input ref={this.handleRefFun} type="text" />
{/* <input ref={el => {
this.text = el;
console.log('查看el的状态', el);
}} type="text" /> */}
<button onClick={this.handleFocus}>点击聚焦</button>
</div>
);
}
}
复制代码
ref调用时间
-
componentDidMount的时候会调用该函数
- 在componentDidMount事件中可以使用ref
-
如果ref的值发生了变动(就的函数被新的函数替代),分别调用旧的函数以及新的函数,时间点出现在componentDidUpdate之前
- 旧的函数被调用时,传递null
- 新的函数被调用时,传递对象(dom元素对象或者实例对象)
-
如果ref所在的组件被卸载,会调用函数
关注我一周带你看一篇对你有帮助的干货!!