• react-ref与ref转发


    ref(reference)引用

    场景: 希望直接使用dom元素中的某个方法(如focus),或者希望直接使用自定义组件中的某个方法

    1. ref作用于内置的html组件,得到的将会是真实的Dom对象
    2. ref作用于类组件,得到将是类的实例
    3. ref不能作用于函数组件
    render() {
    	return (
    		// this.refs.input 得到的是dom对象
    		<input ref='input' />
    	)
    }
    render() {
    	return (
    		// this.refs.input 得到的是实例对象
    		<MyClassComponent ref='input' />
    	)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ref不再推荐使用如上JS代码中的字符串赋值形式 未来可能会移除这种赋值方式
    目前, ref推荐使用对象或者函数

    对象

    通过 React.createRef 创建

    import React, { Component } from 'react'
    
    export default class RefClass extends Component {
      constructor(props) {
        super(props)
        this.input = React.createRef()
      }
      render() {
        return (
          // this.input = { current: Dom对象 }
          // 使用: this.input.current.xxx
          <div ref={this.input}></div>
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    函数

    1. 将函数直接写在ref里
      该函数的执行时机是 componentDidMount, 此时可以使用 this.ele (ps: 本例中)
      当页面重新渲染时,该函数会调用两次, 执行的时机是componentDidUpdate
      第一次调用传入null 本例中打印 ‘调用了’ null
      第二次传入dom对象 本例中打印 ‘调用了’ inputDom元素
    import React, { Component } from 'react'
    
    export default class Ref extends Component {
      handleClick = () => {
        console.log('this', this)
        this.setState({})
      }
      render() {
        return (
          <div>
            <input ref={el=> {
              console.log('调用了', el)
              this.ele = el
            }} type="text" />
            <button onClick={this.handleClick}>点击吧</button>
          </div>
        )
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1. 将函数定义到类里
      调用时机跟之前相同, 不过该函数不会因为页面渲染而重新调用,只会执行一次
    import React, { Component } from 'react'
    
    export default class Ref extends Component {
      handleClick = () => {
        console.log('this', this)
        this.setState({})
      }
      getInputRef = el => {
        console.log('调用了', el)
        this.ele = el
      }
      render() {
        return (
          <div>
            <input ref={this.getInputRef} type="text" />
            <button onClick={this.handleClick}>点击吧</button>
          </div>
        )
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    ref转发 (forwardRef)

    1. 函数组件
      App.js
    import React, { Component } from 'react'
    
    // 2. 被转发的函数组件必须有第二个参数来接受被转发的ref
    function A(props, ref) {
      return (
        // 3. 此时myRef指向h1元素
        <h1 ref={ref}>组件A</h1>
      )
    }
    
    // 1. 通过React.forwardRef可以转发ref, 参数传递***函数***组件,返回一个组件
    const NewA = React.forwardRef(A)
    
    export default class App extends Component {
      myRef = React.createRef()
      componentDidMount() {
        // 4. 得到想要的h1元素
        console.log('myRef', this.myRef)
      }
      render() {
        return (
          <div>
            <NewA ref={this.myRef}/>
          </div>
        )
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    1. 如果类组件也想做转发,可以使用如下方法,当然还有别的方法
    import React, { Component } from 'react'
    
    // 3. 使用约定好的属性forwardRef绑定到h1元素
    class A extends React.Component {
      render() {
        return (
          <h1 ref={this.props.forwardRef}>类组件A</h1>
        )
      }
    }
    
    // 1. 通过React.forwardRef可以转发ref, 参数传递***函数***组件,返回一个组件
    const NewA = React.forwardRef((props, ref) => {
      // 2. 约定一个自定义属性名(本例forwardRef)用于转发ref
      return <A {...props} forwardRef={ref} />
    })
    
    export default class App extends Component {
      myRef = React.createRef()
      componentDidMount() {
        // 4. 得到想要的h1元素
        console.log('myRef', this.myRef)
      }
      render() {
        return (
          <div>
            <NewA ref={this.myRef}/>
          </div>
        )
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    1. 当我们使用高阶组件的时候绑定ref,如果高阶组件不做处理,那么ref将指向这个高阶组件,明显不对,可以使用ref转发完成这种场景的问题

    高阶组件withLog.js

    import React from 'react'
    export default function withLog(Comp) {
      class LogContainer extends React.Component {
        componentDidMount() {
          console.log(`组件: ${Comp.name}被创建了`)
        }
        componentWillUnmount() {
          console.log(`组件: ${Comp.name}被销毁了`)
        }
        render() {
          // 解构属性
          const { forwardRef, ...rest } = this.props
          return (
            // 属性传递
            <Comp ref={forwardRef} {...rest} />
          )
        }
      }
      return React.forwardRef((props, ref)=> {
        // 约定forwardRef用于转发ref
        return <LogContainer {...props} forwardRef={ref}  />
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    App.js

    import React, { Component } from 'react'
    import { A } from './components/testHOC'
    import withLog from './HOC/withLog'
    // 高阶组件
    const AComp = withLog(A)
    
    export default class App extends Component {
      myRef = React.createRef()
      componentDidMount() { 
        // 经过高阶组件处理,现在myRef将指向A组件
        console.log('myRef', this.myRef)
       }
      render() {
        return (
          <div>
            <AComp ref={this.myRef} isLogin a='a' />
          </div>
        )
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    golang - 使用有缓冲通道控制并发数
    中科磐云题目——报错注入 解析(flag)
    数据库第二天 DML操作 DQL查询
    刷爆力扣之较大分组的位置
    应用实战|微信小程序开发示例之在线商城
    猿创征文 | 使用插槽解决组件内容传递问题(1)
    CSDN 云IDE初体验 - 不负所望
    k8s之数据卷
    计算机体系结构第五次实验——Branch-Target Buffers(BTB)
    14:00面试,14:06就出来了,问的问题有点变态。。。
  • 原文地址:https://blog.csdn.net/yuey0809/article/details/126120328