2

我正在学习反应。在我看来,HOC 就像 React 官方文档中的以下示例:

function withSubscription(WrappedComponent, selectData) {
    // ...and returns another component...
    return class extends React.Component {
        constructor(props) {
            super(props);
            this.handleChange = this.handleChange.bind(this);
            this.state = {
                data: selectData(DataSource, props)
            };
        }

        componentDidMount() {
            // ... that takes care of the subscription...
            DataSource.addChangeListener(this.handleChange);
        }

        componentWillUnmount() {
            DataSource.removeChangeListener(this.handleChange);
        }

        handleChange() {
            this.setState({
                data: selectData(DataSource, this.props)
            });
        }

        render() {
            // ... and renders the wrapped component with the fresh data!
            // Notice that we pass through any additional props
            return <WrappedComponent data={this.state.data} {...this.props} />;
        }
    };
}

可以这样改写:

class WithSubscription extends React.Component {
    constructor({ component, selectData, ...props }) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.state = {
            data: selectData(DataSource, props)
        };
    }

    componentDidMount() {
        DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
        DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
        this.setState({
            data: selectData(DataSource, this.props)
        });
    }

    render() {
        return <component data={this.state.data} {...this.props} />;
    }
}

然后像这样使用它:

<WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />

他们都是HOC吗?什么时候一种风格比另一种更受欢迎?

4

3 回答 3

4

起初我也在与 HOC 作斗争。另一种看待这一点的方法是组件的包装器,您可以使用这些包装器将功能与一个组件隔离开来。

例如,我有多个 HOC。我有许多只由 props 定义的组件,并且一旦创建它们就是不可变的。

然后我有一个加载器 HOC 组件,它处理所有网络连接,然后将道具传递给正在包装的任何组件(这将是您传递给 HOC 的组件)。

加载器并不真正关心它正在渲染哪个组件,它只需要获取数据,并将其传递给被包装的组件。

在您的示例中,您实际上可以完成相同的操作,但是一旦您需要链接多个 HOC,它将变得更加复杂。

例如,我有这个 HOC 链:

PermissionsHOC -> LoaderHOC -> BorderLayoutHOC -> 组件

第一个可以检查您的权限,第二个是加载数据,第三个是提供通用布局,第四个是实际组件。

如果您意识到某些组件将受益于在父级上具有通用逻辑,则检测 HOC 会容易得多。您可以在示例中执行相同的操作,但是每次添加子组件时都需要修改 HOC,以添加该子组件的逻辑。不是很有效。这样,您可以轻松添加新组件。我确实有一个每个组件都扩展的 Base 组件,但我用它来处理辅助功能,如分析、记录器、处理错误等。

于 2018-01-20T03:38:08.663 回答
2

他们所谓的“HOC”基本上是一个函数(只是一个常规函数,不是 React 特定的),其行为类似于组件工厂。这意味着它输出包装的组件,这些组件是包装您选择的任何内部组件的结果。您的选择由“WrappedComponent”参数指定。(注意他们所谓的“HOC”实际上是如何返回一个类的)。

所以我不知道他们为什么称它为“HOC”tbh。它只是一个吐出组件的函数。如果有人知道我为什么有兴趣听到原因。

从本质上讲,他们的示例正在做您正在做的事情,但它更灵活,因为 WrappedComponent 被作为参数接收。所以你可以指定任何你想要的。

另一方面,您的代码将您的内部组件硬编码到其中。

要查看他们示例的强大功能,假设您有一个名为 insideComp.js 的文件,其中包含:

import withSubscription from './withSubscription';

class InsideComp extends React.Component{
// define it
}

export default withSubscription(InsideComp);

当您在另一个文件中使用 insideComp 时:

import myComp from './insideComp.js';

您实际上并没有导入 insideComp,而是“withSubscription”已经吐出的包装版本。因为记住你 insideComp.js 的最后一行是

export default withSubscription(InsideComp);

因此,您的 InsideComp 在导出之前已被修改

于 2018-01-20T02:25:01.370 回答
1

第二个不是 HOC。

他们从高阶函数中创造了 HOC 这个词。高阶函数的一个示例是将函数作为参数并返回另一个函数的函数。

类似地,HOC 是一个将组件作为参数并返回另一个组件的函数。

这对我来说听起来很奇怪,因为高阶组件不是反应组件。它是一个函数。我猜他们称之为 HOC 的原因是:

React 组件是一个类,它确实是 JavaScript 中的构造函数(除了功能组件只是函数)。HOC 实际上接受一个函数(一个构造函数)并返回另一个函数(另一个构造函数),所以如果你仔细想想,它实际上是一个高阶函数。可能是因为它在 react 上下文中,并且这是一种转换组件的模式,所以他们称之为 HOC。

至于你提到的两种风格的区别:

第一个:你会使用第一个来生成一个类MyComponnet = withSubscription(AnotherComponent, ...),当你在渲染调用中需要它时,只需编写<MyComponent><MyComponent>

第二个:这不太常见。每次在渲染调用中需要它时,都需要包含描述中提到的 WithSubscription 组件<WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />

于 2018-01-20T04:15:11.223 回答