開始閱讀此篇之前,勸世一下,不要過度使用 Ref,盡量僅限於簡單來說就是 DOM 樣式觸發使用。
有幾種適合使用 ref 的情況:
- 管理 focus、選擇文字、或影音播放。
- 觸發即時的動畫。
- 與第三方 DOM 函式庫整合。
傳送 ref 是一種自動把 ref 從一個 component 傳遞到它底下的其中一個 child 的技巧。
通常來說,應用程式裡大部分的 component 都不需要用到它。然而,對某些種類的 component 來說它很有用,特別是能夠重複使用的函式庫。
深度閱讀官方文件
const ref = React.createRef();
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
<FancyButton ref={ref}>Click me!</FancyButton>;
- 我們藉由呼叫 React.createRef 產生了一個 React ref,然後將它賦值於叫做 ref 的變數裡。
- 我們藉由把 ref 當成一個 JSX attribute 來把它傳遞到 。
- React 把 ref 當作第二個變數傳到 forwardRef 裡的 (props, ref) => … function。
- 我們藉由把這個 ref 當作 JSX attribute 來傳遞到更下面的 。
- 當 ref 被附上之後,ref.current 會指向 DOM 節點。
使用 Ref 時機
React 會在 component mount 的時候將 DOM element 賦值到 current
屬性,並在 unmount 時將它清空回 null。
ref 的更新發生在生命週期 componentDidMount
或 componentDidUpdate
之前。
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 產生一個可以儲存 textInput DOM element 的 ref
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 特別利用原生的 DOM API 來關注文字的輸入
// 注意:我們正利用「current」來取得 DOM 節點
this.textInput.current.focus();
}
render() {
// 告訴 React 我們想要將 <input> ref
// 和我們在 constructor 產生的 `textInput` 連結
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
Callback Refs
React 也支援另一種設定 ref 的方式,這種方法叫做「callback refs」,它提供了對 ref 的設定上更細緻的控制。
不是將 createRef() 所產生的 ref 傳遞下去,而是把一個 function 往下傳。
這個 function 會將 React component 的 instance 或 HTML DOM 作為他的參數,然後可以被儲存之後在別的地方使用。
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => {
this.textInput = element;
};
this.focusTextInput = () => {
// 利用原生的 DOM API 來 focus 文字輸入
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// 在 mount 的時候自動 focus 輸入
this.focusTextInput();
}
render() {
// 利用 `ref` callback 來儲存 instance 欄位裡文字輸入 DOM 的參考
// (例如:this.textInput)
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
OS:這部分先筆記起來,Vue 的 Ref 簡單很多 …,於是我找了一篇技術文章Vue ref vs React refs
在 Higher-Order Component 內傳送 ref
function logProps(Component) {
class LogProps extends React.Component {
render() {
const {forwardedRef, ...rest} = this.props;
// 將自定義道具“forwardedRef”分配為參考
return <Component ref={forwardedRef} {...rest} />;
}
}
// 注意 React.forwardRef 提供的第二個參數“ref”。
// 我們可以將它作為常規道具傳遞給 LogProps,例如“forwardedRef”
// 然後它可以附加到組件。
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
How To Use:
const FancyButton = logProps(class extends React.Component {
force() { /* ... */ }
})
const ref = React.createRef();
<FancyButton ref={ref} /> // 此時 ref.current 就是指向 目標組件,可使用 focus()