面試官: 談一談 HOC、Render props、Hooks

  • 2020 年 3 月 11 日
  • 筆記

在以前我們可能會看到很多文章在分析 HOC 和 render props, 但是在 2020 年 ,我們有了新歡 「hook」 .

本篇文章會分析 hook , render props 和 HOC 三種模式的優缺點. 讓你徹底理解這三種模式. 並且, 告訴你為何應該儘可能使用 hook.

HOC

創建 HOC 的方式

學習 HOC 我們只需要記住以下 2 點定義:

  1. 創建一個函數, 該函數接收一個組件作為輸入除了組件, 還可以傳遞其他的參數
  2. 基於該組件返回了一個不同的組件.

程式碼如下:

function withSubscription(WrappedComponent, selectData) {    return class extends React.Component {      constructor(props) {        super(props);        this.state = {          data: selectData(DataSource, props)        };      }      // 一些通用的邏輯處理      render() {        // ... 並使用新數據渲染被包裝的組件!        return <WrappedComponent data={this.state.data} {...this.props} />;      }    };  }

HOC 的優點

  • 不會影響內層組件的狀態, 降低了耦合度

HOC 的缺點

  • 固定的 props 可能會被覆蓋.
<MyComponent    x="a"    y="b"  />

這 2 個值,如果跟高階組件的值相同, 那麼 x,y 都會被來自高階組件的值覆蓋.

// 如果 withMouse 和 withPage 使用了同樣的 props, 比如 x , y.  // 則會有衝突.  export default withMouse(withPage(MyComponent));
  • 它無法清晰地標識數據的來源

withMouse(MyComponent) 它不會告訴你組件中包含了哪些 props , 增加了調試和修復程式碼的時間.

render props

功能: 將一個組件內的 state 作為 props 傳遞給調用者, 調用者可以動態的決定如何渲染.

創建 render props 的方式

  1. 接收一個外部傳遞進來的 props 屬性
  2. 將內部的 state 作為參數傳遞給調用組件的 props 屬性方法.

程式碼如下:

class Mouse extends React.Component {    constructor(props) {      super(props);      this.state = { x: 0, y: 0 };    }      render() {      return (        <div style={{ height: '100%' }}>          // 使用 render props 屬性來確定要渲染的內容          {this.props.render(this.state)}        </div>      );    }  }  // 調用方式:  <Mouse render={mouse => (    <p>滑鼠的位置是 {mouse.x},{mouse.y}</p>  )}/>

缺點

  • 無法在 return 語句外訪問數據

它不允許在 return 語句之外使用它的數據. 比如上面的例子, 不能在 useEffect 鉤子或組件中的任何其他地方使用 x 和 y 值, 只能在 return 語句中訪問.

  • 嵌套

它很容易導致嵌套地獄. 如下程式碼:

const MyComponent = () => {    return (      <Mouse>        {({ x, y }) => (          <Page>            {({ x: pageX, y: pageY }) => (              <Connection>                {({ api }) => {                  // yikes                }}              </Connection>            )}          </Page>        )}      </Mouse>    )  };

基於上面的兩種方式,都有他們的缺點,那我們來到最香的解決方案: hook

hook

我們來看一個例子:

const { x, y } = useMouse();  const { x: pageX, y: pageY } = usePage();    useEffect(() => {    }, [pageX, pageY]);

從上面的程式碼可以看出, hook 有以下的特性. 它解決了上面 hoc 和 render props 的缺點.

  • hook 可以重命名

如果 2 個 hook 暴露的參數一樣,我們可以簡單地進行重命名.

  • hook 會清晰地標註來源

從上面的例子可以簡單地看到, x 和 y 來源於 useMouse. 下面的 x, y 來源於 usePage.

  • hook 可以讓你在 return 之外使用數據
  • hook 不會嵌套
  • 簡單易懂, 對比 hoc 和 render props 兩種方式, 它非常直觀, 也更容易理解.

總結

在 hook、render props 和 HOC(higher-order components) 之間選擇時,應該儘可能使用 hook.

參考資料

[1]

參考文章: https://dev.to/bettercodingacademy/react-hooks-vs-render-props-vs-higher-order-components-1al0