簡體   English   中英

定義 React HOC 組件的風格

[英]Style of defining React HOC components

因此,在我的 React 應用程序中,我看到了以下定義 HOC 的模式;

export function withMyApi() {
  // Extra function wrapper to allow for clear place for configs.  Plus, you can compose multiple HOCs if necessary
  return function(WrappedComponent) {
    class MyApiUrls extends React.Component {
      constructor(props) {
        super(props);
      }
      render() {
        return <WrappedComponent api={this.api} {...this.props} />;
      }
    }
    return MyApiUrls;
  };
}

以上是如何工作的? HIC 是否在此處返回 function 組件? 上面的方式是故意用來作曲的嗎?

具體來說,HOC 返回 class 組件或 function 組件。 但是,對於上述模式,尚不清楚 HOC 將返回什么。

您問題中的 function 是一個名為withMyApi的 HOF(高階函數),它返回一個匿名function ,它接受一個組件作為WrappedComponent參數,當調用該參數時,它會返回您傳遞的“組件”。

這是使用此 HOF 的語法:

const MyComponent = withMyApi()(MyOriginalComponent)

是的,您可以說withMyApi()(MyOriginalComponent)不必要的工作,它應該只是withMyApi(MyOriginalComponent)

並且我同意。 所以,這里是重構的 HOC:

選項 1 ,使用 class 組件作為包裝器:

export function withMyApiClass(WrappedComponent) {
  return class MyApiUrls extends React.Component {
    constructor(props) {
      super(props)
      this.api = 'http://www.example.com'
    }
    render() {
      return <WrappedComponent api={this.api} {...this.props} />
    }
  }
}

使用上述 HOC 的語法: const Comp1 = withMyApiClass(Comp)

選項 2 ,使用 function 組件作為包裝器:

export function withMyApiFunction(WrappedComponent) {
  return function MyApiUrls(props) {
    const api = useRef('http://www.example.com')
    return <WrappedComponent api={api.current} {...props} />
  }
}

使用上述 HOC 的語法: const Comp1 = withMyApiFunction(Comp)


那么,為什么我們需要withMyApi HOF 的第一種形式(有問題)?

您可能需要也可能不需要,這取決於您的要求。 一個典型的用例是傳遞一些config object。 一個例子:

export function withMyApi(config) {
  const { secure } = config
  return function (WrappedComponent) {
    class MyApiUrls extends React.Component {
      constructor(props) {
        super(props)
        this.api = `http${secure ? 's' : ''}://www.example.com`
      }
      render() {
        return <WrappedComponent api={this.api} {...this.props} />
      }
    }
    return MyApiUrls
  }
}

使用上述 HOF 的語法: const Comp1 = withMyApi({ secure: false })(Comp)

PS:如果你曾經使用過 Redux,你一定見過connect HOF 接受一些 arguments,類似於你的 HOF。

所以編寫 HOF 背后的基本思想是 -將配置參數與組件參數分開,以便人們在有多個 HOC 使用時可以輕松使用compose function


你的問題:

以上是如何工作的?

有問題的 HOC 實際上是高階函數:它返回一個 function ,調用它時返回一個組件。

HOF 是否在此處返回 function 組件?

不,它返回的是 function。 但是當我們調用返回的 function 時,它會返回一個class 組件 請參閱選項 2 ,它返回 function 組件。

上面的方式是故意用來作曲的嗎?

是的,當使用多個 HOC 或 HOF 時,您可以使用 compose 實用程序(來自任何庫,如RamdajsLodashRedux )來創建新的“組合 HOC”。 請參閱最大化可組合性


編輯:

我不喜歡霍夫。 我還能實現組合和配置嗎?

是的,一個例子。 假設我們在HOC下面寫了:

export function withMyApi(WrappedComponent, config) {
  const { secure } = config
  return function MyApiUrls(props) {
    const api = useRef(`http${secure ? 's' : ''}://www.example.com`)
    return <WrappedComponent api={api.current} {...props} />
  }
}

如何使用它?

const Comp1 = withMyApi(Comp, { secure: true })

/* OR, if you want to use more HOCs.
Nested (dirty? Maybe) */
const Comp1 = withRouter(withMyApi(Comp, { secure: true })) 

-----------------------------------------------------------

// But you CAN NOT compose like this:
const composedHOC = compose(
  withRouter,  // a function : OK
  withMyApi(Comp, { secure: false }) // NOT OK. Because is a React Component now.
)
/* It will give error when you will call composedHOC(...) because 
in React, we don't call components using parenthesis i.e. () but 
we invoke then using angle brackets i.e. < />. */

/* After compsing, you CAN NOT do the below otherwise you are going 
to pass `Comp` 2 times to `withMyApi` : Bad/Confusing... :( 
PLUS you will see errors due to calling a React Component using
parenthesis i.e. () as mentioned above. */
const Comp1 = composedHOC(Comp)

-----------------------------------------------------------

// But you can compose like the below:
const composedHOC = compose(
  withRouter, 
  withMyApi
)
const Comp1 = composedHOC(Comp, { secure: false })
/* It will work because it will pass the TWO parameters - "Comp" & 
"{ secure: false }" to LAST (withMyApi) HOC. And the result of that 
will be passed to FIRST HOC (withRouter). */

-----------------------------------------------------------

// But, surprisingly, there will be error when you change the order:
const composedHOC = compose(
  withMyApi, // FIRST
  withRouter // LAST
)
const Comp1 = composedHOC(Comp, { secure: false })
/* Because it will pass the TWO parameters to LAST HOC (withRouter), 
and result of that to FIRST HOC (withMyApi) and So, withMyApi will 
receive ONLY enhanced "Comp" NOT the "{ secure: false }". This is why
using "compose" is buggy for HOCs that acpect config parameters. */

/* Just to remind, this is what a compose function does:
"Composes single-argument functions from right to left. The rightmost 
function can take multiple arguments as it provides the signature for 
the resulting composite function."
compose(f, g, h) is the same as (...args) => f(g(h(...args)))
Means, it pass args to h, and the result to g and then result to f. */

好的,我可能喜歡 HOF。 如何使用 HOF 做同樣的事情?

export function withMyApi(config) {
  const { secure } = config
  return function (WrappedComponent) {
    return function MyApiUrls(props) {
      const api = useRef(`http${secure ? 's' : ''}://www.example.com`)
      return <WrappedComponent api={api.current} {...props} />
    }
  }
}

如何使用它?

const Comp1 = withMyApi({ secure: false })(Comp)

// OR, if you want to use more HOCs
const composedHOC = compose(
  withRouter,
  withMyApi({ secure: false })
)
const Comp1 = composedHOC(Comp) // Looks clean :)

結論:

  1. 如果 HOC 接受“組件”和一個或多個“配置” compose ,則不要將其與 HOC 一起使用。 改用嵌套方法。
  2. 使用嵌套或更好的 - 與 HOF 和 HOC compose (只要 HOC 不接受配置對象)
  3. 當您想要接受一個/多個配置對象時,最好編寫 HOF。 這樣,人們就可以將compose與您的 HOF 一起使用。

如果您想通過 function 的附加參數來支持“配置”,HOF 會更好/更清潔。

這種(HOF)形式可能看起來令人困惑或不必要,但它有一個有用的屬性。 像連接 function 返回的單參數 HOC 具有簽名 Component => Component。 output 類型與其輸入類型相同的函數非常容易組合在一起。

它實際上返回一個 function,您將使用它返回一個 Class 組件。

我認為混淆在於 HOC 的概念,因為上面帶有包裝器 function 的模式。

這種模式允許我們在不破壞 HOC 概念的情況下增強我們的組件。

我們需要維護 HOC 的概念,但我們可能需要添加額外的配置或組合多個組件,上述模式將很有用。

Component => Component

上面變成:

WrapperFunction()(Component) => Component

但我們可以想知道為什么不直接通過 HOC 傳遞另一個 args:

HOC(Component, <any extra config we want>)

HOC 說,它需要一個組件並返回一個組件,而額外的參數似乎並不是很積極,不是嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM