返回
Featured image of post React - Refs

React - Refs

React - Refs,從頭學React

開始閱讀此篇之前,勸世一下,不要過度使用 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>;
  1. 我們藉由呼叫 React.createRef 產生了一個 React ref,然後將它賦值於叫做 ref 的變數裡。
  2. 我們藉由把 ref 當成一個 JSX attribute 來把它傳遞到 。
  3. React 把 ref 當作第二個變數傳到 forwardRef 裡的 (props, ref) => … function。
  4. 我們藉由把這個 ref 當作 JSX attribute 來傳遞到更下面的 。
  5. 當 ref 被附上之後,ref.current 會指向 DOM 節點。

使用 Ref 時機

React 會在 component mount 的時候將 DOM element 賦值到 current 屬性,並在 unmount 時將它清空回 null。
ref 的更新發生在生命週期 componentDidMountcomponentDidUpdate 之前。

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()
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus