繁体   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