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' />
	)
}

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. 将函数直接写在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. 将函数定义到类里
    调用时机跟之前相同, 不过该函数不会因为页面渲染而重新调用,只会执行一次
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>
    )
  }
}

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. 如果类组件也想做转发,可以使用如下方法,当然还有别的方法
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. 当我们使用高阶组件的时候绑定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}  />
  })
}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

合法的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值