React Hooks之useRef、createRef、forwardRef
一 Ref(reference)引用:用于直接使用dom元素的某个方法,或者直接使用自定义组件中的某个方法。处理对象:管理焦点,文本选择,媒体播放(媒体回放);触发动画;集成第三方的DOM库。
- 作用于内置的html组件,得到的是真实的dom
- ref作用于类组件,得到的是类的实例
- ref不能作用于函数组件
- Ref不推荐字符串方式,一般是函数或者对象方式引用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import React, { Component, createRef } from 'react'; export default class Test extends Component { constructor(props){ super(props) this.createRefTxt = createRef() } handleFnClick = () => { console.log(this.fnTxt); this.fnTxt.focus(); }; handleObjectClick = () => { console.log(this.createRefTxt); this.createRefTxt.current.focus(); }; render () { return ( <> <div className="func-way"> <input ref={(el) => { this.fnTxt = el; }} type='text' /> <button onClick={this.handleFnClick}>函数方式</button> </div> <div className="object-way"> <input ref={this.createRefTxt} type='text' /> <button onClick={this.handleObjectClick}>对象方式</button> </div> </> ); } }
二 useRef、createRef、forwardRef区别:
1 useRef:
一般用于函数组件
useRef 不仅仅是用来管理 DOM ref 的,它还相当于 this , 可以存放任何变量。
当 useRef 的内容发生变化时,它不会通知您。更改.current属性不会导致组件重新渲染。因为他一直是一个引用 。
2 createRef:
一般用于类组件,React.createRef 创建一个能够通过 ref 属性附加到 React 元素的 ref。
如果用于函数组件中,当App这个函数组件被重新渲染时,App函数将会执行,并且重新创建、初始化所有的变量和表达式。因此,createRef每次都会被执行,所以对应的值总是为null。
createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用。
3 forwardRef:
Ref 转发是一个可选特性,其允许某些组件接收 ref,并将其向下传递(换句话说,“转发”它)给子组件。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import React, { Component } from 'react' function A(props, ref){ console.log(props, ref) return <h1 ref={ref}>A组件</h1> } // 传递函数组件,得到一个新的组件,不能传递类组件,并且函数组件必须使用第二个 const NewA = React.forwardRef(A) export default class Test extends Component { ARef = React.createRef() componentDidMount() { console.log(this.ARef) // {current: h1} } render() { return ( <div> <NewA ref={this.ARef} words="sdfsd"/> </div> ) } }
4 父组件调用子组件方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import React, { Component, createRef } from 'react'; class CustomTextInput extends Component { constructor(props) { super(props); this.focus = this.focus.bind(this); } focus () { // Explicitly focus the text input using the raw DOM API this.textInput.focus(); } handleChild = () => { console.log('父组件调用子组件方法') } render () { // Use the `ref` callback to store a reference to the text input DOM // element in an instance field (for example, this.textInput). return ( <div> <input type="text" ref={(input) => { this.textInput = input; }} /> {/* //此时input参数就是表示该DOM本身 */} <input type="button" value="Focus the text input" onClick={this.focus} /> </div> ); } } export default class Test extends Component { componentDidMount () { console.log(this.textInput); //父组件自动调用子组件CustomTextInput实例的focus方法 this.textInput.focus(); } handleClick = () => { this.textInput.handleChild(); } render () { return ( <div> <CustomTextInput ref={(input) => { this.textInput = input; }} /> <button onClick={this.handleClick}>父组件按钮</button> </div> ); } }
三 useRef与createRef更新:useRef与createRef更新区别
能够获取上一次值的原因:由于 useEffect
在 Render 完毕后才执行,因此 ref
的值在当前 Render 中永远是上一次 Render 时候的,我们可以利用它拿到上一次 Props
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import React, { useState, createRef, useRef, useEffect } from 'react'; const Child1 = () => { const [count, setCount] = useState(0); const preCountUserRef = useRef(); console.log(count); useEffect(() => { preCountUserRef.current = count; }); return ( <div> <p>preCount:{preCountUserRef.current}</p> <p>You clicked {count} times</p> <button onClick={() => { setCount(count + 1) }}>Click me</button> </div> ) } export default Child1