react - 07.forwardRef

57 阅读2分钟

1.forwardRef语法:

React.forward(render)

forwardRef函数接收一个名为render的函数,也可以理解为一个函数组件,返回值是react组件

const render = (props, ref) => {
  return <></>
}

render函数接收2个参数

第一个参数是props(父组件传递的参数对象)

第二个是ref(React.createRef())

所以就组成了我们常见的写法

const Button = React.forwardRef((props, ref)) {
  return <></>
}

2.forwardRef的作用以及正确和错误的使用方法:

需要注意的是,ref的作用是获取实力,如果目标组件是一个自定义函数,那么它是没有实例的,此时用ref去传递会报错,因为ref无法获取到实例,但是forwardRef就可以解决这个问题

forwardRef会创建一个React组件,这个组件能够将其接收的ref属性转发到自己的组件树上

假设我们实现一个,在父组件中获取子组件的input元素,然后设置input焦点,我们怎么实现呢?如果要是直接用useRef,那么会报错,因为自定义函数组件是没有实例的,所以ref显示获取不到实例,因此react就会报错,例如:

import { useRef } from 'react'
const Child = (props:any) => {
  return (
    <input ref={props.ref} />
  )
}
const App = () => {
  const inputRef = useRef(null)
  console.log(inputRef)
  return (
    <div>
      <Child ref={inputRef}></Child>
    </div>
  )
}
export default App

这个时候会发现控制台报错了,react不支持这种做法

所以我们用forwardRef来解决实现获取子组件的dom元素:

import { forwardRef, useEffect, useRef } from 'react'
const Child = forwardRef((props: any, ref: any) => {
  return (
    <input ref={ref} />
  )
})
const App = () => {
  const inputRef = useRef<HTMLInputElement>(null)
  useEffect(() => {
    console.log(inputRef)
    inputRef.current?.focus()
  }, [])
  return (
    <div>
      <Child ref={inputRef}></Child>
    </div>
  )
}
export default App

3.forwardRef的注意事项:

1.ref必须指向DOM元素

假设我们声明父组件,子组件,孙组件,我想在父组件获取孙组件的dom,我这样写,是报错的:

import { forwardRef, useRef } from 'react'
const B = (props:any) => {
  return (
    <div ref={props.ref}></div>
  )
}
const A = forwardRef((props:any,ref:any) => {
  return (
    <div>
      <B ref={ref}></B>
    </div>
  )
})
const App = () => {
  const ref = useRef(null)
  console.log(ref)
  return (
    <div>
      <A ref={ref}></A>
    </div>
  )
}
export default App

因为我们并没有让ref指向dom元素,修改方法是:

import { forwardRef, useRef } from 'react'
// 定义一个孙组件B,并在B组件中接收传递过来的ref对象
const B = (props:any) => {
  return (
    <div ref={props.ref}></div>
  )
}
// 定义A组件,在A组件中使用B组件,并把从父组件传递过来的ref对象传递给B组件
const A = forwardRef((props:any,ref:any) => {
  return (
    <div ref={ref}>
      <B></B>
    </div>
  )
})
// 在父组件使用A组件,并且把useRef创建的ref对象传递给A组件
const App = () => {
  const ref = useRef(null)
  console.log(ref)
  return (
    <div>
      <A ref={ref}></A>
    </div>
  )
}
export default App

2.forwardRef可以应用到高阶组件中