简体   繁体   English

反应-应该将高阶组件编写为函数吗?

[英]React - should Higher Order Component be written as a function?

I'm learning React. 我正在学习React。 It seems to me that HOC like the following example from React's official docs : 在我看来,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} />;
        }
    };
}

can be rewritten in this way: 可以这样重写:

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} />;
    }
}

Then use it like this: 然后像这样使用它:

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

Are they both HOC? 他们都是HOC吗? When is one style preferred than the other? 什么时候一种风格比另一种更好?

I was struggling with HOC too at first. 一开始,我也在HOC方面挣扎。 Another way of looking at this is at wrappers of components that you could use to isolate the functionality from one component. 另一种查看方式是组件包装,您可以使用这些组件将功能与一个组件隔离。

For example, I have multiple HOC. 例如,我有多个HOC。 I have many components that are only defined by props, and they are immutable once they are created. 我有许多仅由props定义的组件,一旦创建,它们是不可变的。

Then I have a Loader HOC Component, which handles all the network connectivity and then just passes the props to whatever component is wrapping (This would be the component you pass to the HOC). 然后,我有一个Loader HOC组件,该组件处理所有网络连接,然后将道具传递给要包装的任何组件(这就是您传递给HOC的组件)。

The loader does not really care which component it is rendering, it only needs to fetch data, and pass it to the wrapped component. 加载程序并不真正在乎它正在渲染哪个组件,它只需要获取数据并将其传递给包装的组件。

In your example, you can actually accomplish the same, however it will become much more complex once you need to chain multiple HOC. 在您的示例中,您实际上可以完成此操作,但是一旦您需要链接多个HOC,它将变得更加复杂。

For example I have this chain of HOCs: 例如,我有此HOC链:

PermissionsHOC -> LoaderHOC -> BorderLayoutHOC -> Component PermissionsHOC-> LoaderHOC-> BorderLayoutHOC-> Component

First one can check your permissions, second one is loading the data, third one is giving a generic layout and the forth one is the actual component. 第一个可以检查您的权限,第二个可以加载数据,第三个可以提供通用布局,第四个是实际组件。

It is much easier to detect HOCs if you realize that some components would benefit from having a generic logic on the parent. 如果您意识到某些组件将从父级上的通用逻辑中受益,则检测HOC会容易得多。 You could do the same in your example, however you would need to modify the HOC every time you add a child component, to add the logic for that one. 您可以在示例中执行相同的操作,但是每次添加子组件时都需要修改HOC,以添加该子组件的逻辑。 Not very effective. 不是很有效。 This way, you can add new components easily. 这样,您可以轻松添加新组件。 I do have a Base component which every component extends, but I use it to handle the helper functions like analytics, logger, handling errors, etc. 我确实有一个Base组件,每个组件都可以扩展,但是我用它来处理诸如分析,记录器,处理错误等辅助功能。

What they call an "HOC" is basically a function (just a regular function, not React specific) that behaves like component factory. 他们所谓的“ HOC”基本上是一个功能类似于组件工厂的函数(只是一个常规函数,不是特定于React的)。 Meaning it outputs wrapped components that are the result of wrapping any inside-component of your choice . 这意味着它会输出包装的组件,这些组件是包装您选择的任何内部组件的结果 And your choice is specified with the "WrappedComponent" parameter. 您的选择由“ WrappedComponent”参数指定。 (Notice how their so-called "HOC" actually returns a class). (请注意,他们所谓的“ HOC”实际上是如何返回一个类的)。

So I don't know why they called it an "HOC" tbh. 所以我不知道为什么他们称其为“ HOC” TBH。 It's just a function that spits out components. 它只是一个吐出组件的函数。 If anyone knows why I'd be interested in hearing the reason. 如果有人知道为什么我会对听到这个原因感兴趣。

In essence their example is doing exactly what you're doing, but it's more flexible because WrappedComponent is being taken in as a parameter. 从本质上讲,他们的示例确实在执行您的操作,但是它更灵活,因为WrappedComponent被作为参数使用。 So you can specify whatever you want. 因此,您可以指定任何内容。

Your code, on the other hand, has your inside component hard coded into it. 另一方面,您的代码将内部组件硬编码到其中。

To see the power of their example, let's say you have a file called insideComp.js containing: 为了查看他们的示例的强大功能,假设您有一个名为insideComp.js的文件,其中包含:

import withSubscription from './withSubscription';

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

export default withSubscription(InsideComp);

And when you use insideComp in another file: 当您在另一个文件中使用insideComp时:

import myComp from './insideComp.js';

You're not actually importing insideComp, but rather the wrapped version that "withSubscription" had already spit out. 您实际上不是在导入insideComp,而是在导入“ withSubscription”已经包装好的版本。 Because remember your last line of insideComp.js is 因为请记住您的insideComp.js最后一行是

export default withSubscription(InsideComp);

So your InsideComp was modified before it was exported 因此,您的InsideComp在导出之前已被修改

The second one is not a HOC. 第二个不是HOC。

They coin the word HOC from higher order functions . 他们从高阶函数中创造了HOC一词。 One example of a higher order function is a function that takes a function as an argument and returns another function. 高阶函数的一个示例是将函数作为参数并返回另一个函数的函数。

Similarly, a HOC is a function that takes an component as argument and returns another component. 类似地,HOC是将一个组件作为参数并返回另一个组件的函数。

This does sound weird to me because a higher order component is not a react component; 这对我来说确实很奇怪,因为高阶分量不是反应分量。 it is a function instead. 它是一个函数。 I guess the reason they call it HOC is because: 我猜他们称其为HOC的原因是:

A react component is a class, which is indeed a constructor function in JavaScript (except that functional components are simply functions). React组件是一个类,它实际上是JavaScript中的构造函数(除了功能组件只是函数)。 A HOC actually takes a function (a constructor function) and returns another function (another constructor function), so it is actually a higher order function if you think about it. HOC实际上需要一个函数(一个构造函数)并返回另一个函数(另一个构造函数),因此,考虑一下它实际上是一个高阶函数。 Probably because it is in the react context and this is a pattern to transform components, they call it HOC. 可能是因为它在react上下文中,并且这是转换组件的一种模式,因此他们将其称为HOC。

As to the difference between the two styles you mentioned: 关于您提到的两种样式之间的区别:

First one: you would use the first one to generate a class like MyComponnet = withSubscription(AnotherComponent, ...) , and whenever you need it in a render call just write <MyComponent><MyComponent> 第一个:您将使用第一个生成类似MyComponnet = withSubscription(AnotherComponent, ...) ,只要在渲染调用中需要它,只需编写<MyComponent><MyComponent>

Second one: this is less common. 第二个:这不太常见。 Every time you need it in a render call, you would need to include the WithSubscription component as you mentioned in the description <WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} /> 每次在渲染调用中需要它时,都需要包含描述中所述的<WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM