在 vue 和 react 的使用中,都有涉及到 ref,除了定义变量之外,ref 的一个重要用处就是绑定 dom 节点或组件,那在 vue 和 react 中,关于 ref 的用法有什么相同与不同呢,我们来一起看看。
1. ref 在 react 中的使用
在 react 中提供了名为 useRef 的 hook 来创建 ref , 既可以保存变量,又可以用来绑定 dom。
a. 绑定单节点
import { useRef } from "react"
function App() {
  // 定义 ref
  const inputRef = useRef(null)
  const handleClick = () => {
    console.log(inputRef.current)
    inputRef.current.focus()
  }
  return (
    <>
      <input ref={inputRef} type="text"/>
      <button onClick={handleClick}>focus the input</button>
    </>
  )
}
b. 绑定多节点
import { useRef, useState } from "react"
function App() {
  const [list] = useState([1, 2, 3, 4, 5])
  const listRef = useRef([])
  const formatRef = (el) => {
    listRef.current.push(el);
  }
  const handleClick = () => {
    console.log(listRef.current);
  }
  return (
    <>
      <ul>
        {list.map((v) => {
          return (
            <li ref={formatRef} key={v}>
              {v}
            </li>
          )
        })}
      </ul>
      <button onClick={handleClick}>获取dom节点</button>
    </>
  )
}
c.绑定组件实例
class组件添加ref
class MyTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  componentDidMount() {
    this.textInput.current.focusTextInput();
  }
  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}
在函数组件中,这样使用 ref 是无效的,可以使用 forwardRef,或者可以将该组件转化为 class 组件。不过,在函数组件内部同样可以使用 ref 属性,只要它指向一个 dom 元素或 class 组件。
使用forwardRef 与useImperativeHandle 进行ref转发,并指定子组件暴露的内容
import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react'
function MyInput(props,ref) {
  const inputRef = useRef()
  useEffect(() => {
    console.log('inputRef',inputRef)
  },[])
  useImperativeHandle(ref, () => ({
    input: inputRef.current,
    focus:() => inputRef.current.focus()
  }))
  return (
    <input ref={inputRef} {...props} />
  )
}
export default forwardRef(MyInput)
import React, { useEffect, useRef } from 'react'
import MyInput from './MyInput' 
export default function App() {
  const input_ref = useRef()
  useEffect(() => {
    console.log(input_ref.current)
    input_ref.current?.focus()
  }, [])
  return (
    <MyInput ref={input_ref} />
  )
}
2. ref在vue中的使用
在 vue 中则是提供了 ref 来声明响应式变量,或者进行 dom 操作。
a. 绑定单节点
<script setup>
import { ref } from "vue"
const inputRef = ref()
const handleClick = () => {
  console.log(inputRef.value)
  inputRef.vaule.focus()
}
</script>
<template>
  <input ref="inputRef" type="text" />
  <button @click="handleClick">获取input焦点</button>
</template>
b.绑定多节点
<script setup>
import { ref, reactive } from "vue"
const list = reactive([1, 2, 3, 4, 5])
const listRef = ref([])
const formatRef = (el) => {
  if (el) {
    listRef.value.push(el)
  }
}
const handleClick = () => {
  console.log(listRef.value)
}
</script>
<template>
  <ul>
    <li v-for="item in list" :key="item" :ref="formatRef">
      {{ item }}
    </li>
  </ul>
  <button @click="handleClick">获取dom节点</button>
</template>
c.绑定组件实例
// 子组件
<script setup>
import { ref, expose } from "vue"
defineProps({
  title: String
})
const inputRef = ref()
const desc = ref('描述')
const focus = () => {
  if(inputRef.value) {
    inputRef.value.focus()
    console.log('focus')
  }
}
expose({
  focus
})  
</script>
<template>
  <div>
    <h3>{{ title }}</h3>
    <input ref="inputRef" type="text" />
    <button @click="handleClick">获取input焦点</button>
  </div>
</template>
// 父组件
<script setup>
import { ref, expose } from "vue"
import Child from 'child.vue'
const childRef = ref()
onMounted(() => {
  console.log(childRef.value)
  console.log(childRef.value?.desc)
  console.log(childRef.value?.focus())
})  
</script>
<template>
  <div>
    <Child ref="childRef" />
  </div>
</template>
本文主要介绍 vue 和 react 中 通过 ref 绑定 dom 元素或组件实例的用法区别,两者使用方法总体来讲还是大致相近的。