目錄
- 1. ref 的基本概念
- 2. 如何使用 ref
- 2.1 基本用法
- 2.2 類組件使用 createRef
- 3. forwardRef 轉發 ref
- 4. ref 的應用場景
- 5. ref 和函數組件
- 總結
在 React 中,ref
(引用)用于訪問 DOM 元素或類組件實例。它允許我們直接與元素進行交互,而不需要依賴 React 的數據流。
下面是關于 React 元素接收 ref
的詳細解釋。
1. ref 的基本概念
React 中的 ref
主要有兩種類型:
- 字符串
ref
:React 16.3 之前的用法,已經被廢棄,不推薦使用。 - 回調
ref
:提供一個函數,將ref
作為參數傳遞給該函數。可以訪問 DOM 元素或組件實例。 createRef()
或者useRef()
:推薦的現代用法,允許創建一個ref
對象,該對象可以用于訪問 DOM 元素或類組件實例。
2. 如何使用 ref
2.1 基本用法
函數組件為例:
import React, { useRef, useEffect } from 'react';const MyComponent = () => {const myRef = useRef<HTMLInputElement>(null);useEffect(() => {if (myRef.current) {myRef.current.focus(); // 聚焦到 input 元素}}, []);return <input ref={myRef} />;
};export default MyComponent;
在這個例子中,我們使用了 useRef
鉤子創建一個 ref
,并將它傳遞給一個 <input>
元素。這樣,myRef.current
就指向該 input
元素,我們可以在 useEffect
中直接操作 DOM。
這里有一個技巧,前面提過 ref 支持接收回調函數,因此我們可以讓代碼更加簡潔:
import React, { useCallback } from 'react';const MyComponent = () => {const myRef = useCallback((node) => node?.focus(), [])return <input ref={myRef} />;
};export default MyComponent;
它的工作原理如下:
- 當 DOM 節點添加到屏幕時,React 會以 DOM 節點作為參數調用該函數。
- 當 DOM 節點被移除時,React 會以 null 調用該函數。
2.2 類組件使用 createRef
在類組件中,我們通常使用 React.createRef()
來創建 ref
。
import React, { Component } from 'react';class MyComponent extends Component {private myRef = React.createRef<HTMLInputElement>();componentDidMount() {if (this.myRef.current) {this.myRef.current.focus();}}render() {return <input ref={this.myRef} />;}
}export default MyComponent;
3. forwardRef 轉發 ref
如果你要在函數組件中使用 ref
,并且希望該 ref
被傳遞到子組件中,你需要使用 React.forwardRef
來轉發 ref
。
import React, { forwardRef, useImperativeHandle, useRef } from 'react';interface CustomInputProps {label: string;
}const CustomInput = forwardRef<HTMLInputElement, CustomInputProps>((props, ref) => {const inputRef = useRef<HTMLInputElement>(null);// 允許父組件操作子組件的方法useImperativeHandle(ref, () => ({focus: () => {if (inputRef.current) {inputRef.current.focus();}}}));return (<div><label>{props.label}</label><input ref={inputRef} /></div>);
});export default CustomInput;
在這個例子中,CustomInput
是一個函數組件,它通過 forwardRef
接收外部的 ref
。我們通過 useImperativeHandle
將自定義的方法(如 focus
)暴露給父組件。
在父組件使用時:
import React, { useRef } from 'react';
import CustomInput from './CustomInput';const ParentComponent = () => {const inputRef = useRef<{ focus: () => void }>(null);return (<div><CustomInput ref={inputRef} label="Username" /><button onClick={() => inputRef.current?.focus()}>Focus Input</button></div>);
};export default ParentComponent;
4. ref 的應用場景
- 訪問 DOM 元素:如上述例子,
ref
允許你直接訪問 DOM 元素并操作其屬性,例如聚焦、滾動、選擇文本等。 - 與第三方庫集成:很多第三方庫(如 D3.js 或 jQuery)需要直接操作 DOM 元素,這時
ref
就非常有用。 - 獲取組件實例:雖然不推薦直接訪問組件實例,但如果需要,可以通過
ref
來訪問類組件的實例方法。
5. ref 和函數組件
默認情況下,ref
只能用于類組件或 DOM 元素。如果你嘗試將 ref
直接傳遞給一個函數組件,React 會給出警告,表示函數組件無法接收 ref
。為了讓函數組件能夠接收 ref
,你需要使用 React.forwardRef
。
總結
ref
是 React 中訪問 DOM 或組件實例的一種方式。- 函數組件無法直接使用
ref
,需要使用React.forwardRef
轉發ref
。 ref
可以配合useImperativeHandle
定制暴露給父組件的接口。ref
對于與第三方庫集成和直接操作 DOM 元素非常有用。