在 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 元素或組件實例的用法區別,兩者使用方法總體來講還是大致相近的。