组件和高阶组件区别_了解高阶组件

本文探讨了React中的高阶组件(HOCs),解释了它们如何帮助实现组件的复用和关注点分离。作者通过介绍组件、状态、全局状态管理、容器组件和表现组件的概念,逐步引导读者理解HOC在React生态系统中的作用。文章还提供了HOC的示例,包括Redux的`connect()`函数,React Router的`withRouter()`,以及Apollo的`graphql()`函数。最后,鼓励读者在需要时创建自定义HOC以提高代码的模块化和可维护性。
摘要由CSDN通过智能技术生成

组件和高阶组件区别

by Tom Coleman

由汤姆·科尔曼(Tom Coleman)

了解高阶组件 (Understanding Higher Order Components)

了解快速变化的React最佳实践。 (Making sense of the rapidly changing React best practice.)

If you’re new to React, you may have heard about “Higher Order Components” and “Container” components. If so, you may be wondering what all the fuss is about. Or you may have even used an API for a library that provides one, and been a little confused about the terminology.

如果您是React的新手,您可能听说过“高阶组件”和“容器”组件。 如果是这样,您可能想知道所有这些大惊小怪。 或者,您甚至可能为提供一个库的库使用了API,并且对该术语有些困惑。

As a maintainer of Apollo’s React integration — a popular open source library that makes heavy use of High Order Components — and the author of much of its documentation, I’ve spent a bit of time getting my head around the concept myself.

作为Apollo的React集成的维护者(一个广泛使用High Order Components的流行的开源库),以及其许多文档的作者,我花了一些时间亲自了解这个概念。

I hope this post can help shed some light on the subject for you too.

我希望这篇文章也能为您提供一些启发。

一个React Re-primer (A React re-primer)

This post assumes that you are familiar with React — if not there’s a lot of great content out there. For instance Sacha Greif’s 5 React Concepts post is a good place to start. Still, let’s just go over a couple of things to get our story straight.

这篇文章假定您熟悉React –否则就没有很多很棒的内容。 例如,Sacha Greif的5 React Concepts帖子是一个不错的起点。 尽管如此,让我们只看几件事就可以使我们的故事清楚。

A React Application consists of a set of components. A component is passed a set of input properties (props) and produces some HTML which is rendered to the screen. When the component’s props change, it re-renders and the HTML may change.

React应用程序由一组组件组成 。 组件将传递一组输入属性( props ),并生成一些呈现到屏幕上HTML。 当组件的props更改时,它会重新渲染并且HTML可能会更改。

When the user of the application interacts with that HTML, via some kind of event (such as a mouse click), the component handles it either by triggering a callback prop, or changing some internal state. Changing internal state also causes it and its children to re-render.

当应用程序的用户通过某种事件(例如,单击鼠标)与HTML进行交互时,组件将通过触发回调道具或更改某些内部状态来对其进行处理 。 改变内部状态也会导致其及其子级重新渲染。

This leads to a component lifecycle, as a component is rendered for the first time, attached to the DOM, passed new props, etc.

这会导致组件生命周期 ,因为组件是首次渲染,附加到DOM,传递新的道具等。

A component’s render function returns one or instances of other components. The resultant view tree is a good mental model to keep in mind for how the components of the app interact. In general they interact only by passing props to their children or triggering callbacks passed by their parents.

组件的render函数返回一个或其他组件的实例。 生成的视图树是记住应用程序组件如何交互的良好心理模型。 通常,它们仅通过将道具传递给孩子或触发其父母传递的回调来进行交互。

ReactUI与状态 (React UI vs statefulness)

It seems almost dated now, but there was a time where everything was described in terms of the distinction between Models, Views and Controllers (or View Models, or Presenters, etc). In this classification, a View’s task is to render and deal with user interaction, and a Controller’s is to prepare data.

现在看来似乎已经过时了,但是有一段时间曾经根据模型,视图和控制器(或视图模型或演示者等)之间的区别来描述所有内容。 在这种分类中,View的任务是呈现和处理用户交互,而Controller的任务是准备数据

A recent trend in React is towards functional stateless components. These simplest “pure” components only ever transform their props into HTML and call callback props on user interaction:

React的最新趋势是朝着功能性无状态组件发展 。 这些最简单的“纯”组件只能将其支持转换为HTML,并在用户交互时调用回调支持:

They are functional because you can really think of them as functions. If your entire view tree consisted of them you are really talking about one big function to produce HTML composed of calls to many smaller ones.

它们是有功能的,因为您可以真正将它们视为功能。 如果您的整个视图树都由它们组成,那么您实际上是在谈论一个大型函数,该函数生成由许多较小的调用组成HTML。

A nice property of functional stateless components is that they are super-easy to test, and simple to understand. This means they are easier to develop and quicker to debug.

功能性无状态组件的一个不错的特性是它们非常易于测试,并且易于理解。 这意味着它们更易于开发且调试更快。

But you can’t always get away with this. UI does need state. For instance, your menu may need to open when the user hovers over it (ugh, I hope not!)—and the way to do this in React is certainly by using state. To use state, you use class-based components.

但是您不能总是摆脱这种情况。 UI确实需要状态。 例如,当用户将鼠标悬停在菜单上时,可能需要打开菜单(嗯,我希望不要!),而React中的方法肯​​定是使用状态。 要使用状态,请使用基于类的组件。

Where things get complicated is wiring the “global state” of your UI into the view tree.

使事情变得复杂的地方是将UI的“全局状态”连接到视图树中。

全球状态 (Global State)

Global state in your UI is the state that isn’t directly and uniquely relevant to a single component. It typically consists of two main types of things:

UI中的全局状态是与单个组件不直接且唯一相关的状态。 它通常由两种主要类型的事物组成:

1. The data in your application that has come from some server. Typically the data is used in multiple places and so is not unique to a single component.

1.您的应用程序中的数据来自某个服务器。 通常,数据在多个位置使用,因此不是单个组件唯一的。

2. Global UI state, (like the URL, and thus which page the user is looking at).

2. 全局UI状态 (如URL,以及用户正在查看的页面)。

One approach to global state is to attach it to the highest “root” component in your app and pass it down the tree to all the components that need it. You then pass all changes to that state back up the tree via a chain of callbacks.

全局状态的一种方法是将其附加到应用程序中最高的“根”组件,然后将其沿树传递给需要它的所有组件。 然后,您通过一系列回调将对状态的所有更改传递回树。

This approach gets unwieldy pretty quickly, though. It means the root component needs to understand the requirements of its entire tree, and likewise for every parent of every subtree in the entire tree. That’s where this next concept comes in.

不过,这种方法很快就会变得笨拙。 这意味着根组件需要了解整个树的需求,并且同样需要了解整个树中每个子树的每个父节点。 这就是下一个概念出现的地方。

容器和演示组件 (Containers and Presentational Components)

This problem is typically solved by allowing components to access global state anywhere in the view tree (some restraint is typically called for).

通常通过允许组件访问视图树中任何位置的全局状态来解决此问题(通常需要采取一些限制措施)。

In this world, components can be classified into those that access the global state, and those that don’t.

在这个世界上,可以将组件分为访问全局状态的组件和不访问全局状态的组件。

The “pure” components that do not are the easiest to test and understand (especially if they are functional stateless components). A soon as a component is “impure” it’s tainted and harder to deal with.

并非最容易测试和理解的“纯”组件(尤其是如果它们是功能性无状态组件)。 一旦某个组件“不纯”,它就会受到污染并且难以处理。

For this reason, a pattern has emerged to separate each “impure” component into two components:

出于这个原因, 一个图案已经出现于每个“不纯的”组分相分离成两个分量:

  • The container component that does the “dirty” global state work

    执行“脏”全局状态工作的容器组件

  • The presentational component that does not.

    表示组件没有。

We can now treat the presentational component just like we treated our simple components above, and isolate the dirty, complex data handling work in the container.

现在,我们可以像对待上面的简单组件一样对待表示性组件,并在容器中隔离脏的,复杂的数据处理工作。

容器 (The container)

Once you’re on board with the presentational/container component split, writing container components becomes interesting.

一旦您准备好将演示文稿/容器组件拆分,编写容器组件就变得很有趣。

One thing you notice is they often don’t look a lot like a component at all. They might:

您注意到的一件事是,它们通常看起来根本不像组件。 他们可能:

  • Fetch and pass one piece of global state (say from Redux) into their child.

    获取并传递一个全局状态(例如,来自Redux)到他们的孩子中。
  • Run one data-accessing (say GraphQL) query and pass the results into their child.

    运行一个数据访问(例如GraphQL)查询,并将结果传递给其子级。

Also, if we follow a good separation of concerns, our containers will only ever render a single child component. The container is necessarily tied to the child, because the child is hardwired in the render function. Or is it?

另外,如果我们将关注点很好地隔离开,那么我们的容器将只会呈现单个子组件 。 容器必须与子级绑定,因为子级在渲染功能中是硬连线的。 还是?

泛化容器 (Generalizing containers)

For any “type” of container component (for instance one that access Redux’s store), the implementation looks the same, differing only in the details: which child component they render, and what exact data they are fetching.

对于任何“类型”的容器组件(例如访问Redux商店的容器组件),实现看起来都是相同的,只是在细节上有所不同:它们呈现的是哪个子组件,以及它们要获取的确切数据是什么。

For example, in the world of Redux (if we didn’t have react-redux's connect HOC) a container might look like:

例如,在Redux的世界中(如果我们没有react-reduxconnect HOC),容器可能看起来像:

Even though this container doesn’t do most of what a true Redux container would do, you can already see that apart from the implementation of mapStateToProps and the specific MyComponent that we are wrapping, there is a lot of boilerplate that we would have to write every single time we write a Redux-accessing container.

即使此容器不能完成真正的Redux容器的大部分工作,您已经可以看到,除了mapStateToProps的实现和我们要包装的特定MyComponent ,还有很多样板需要编写每次我们编写一个Redux访问容器

生成容器 (Generating Containers)

In fact, it might be simpler just to write a function that generates the container component based on the pertinent information (in this case the child component and the mapStateToProps function).

实际上,仅编写一个基于相关信息生成容器组件的函数(在这种情况下为子组件和mapStateToProps函数)可能会更简单。

This is a Higher Order Component (HOC), which is a function that takes a child component and some options, then builds a container for that child.

这是一个高阶组件 (HOC),该函数需要一个子组件和一些选项,然后为该子组件构建一个容器。

It’s “higher order” in the same way as a “higher order function” — a function that builds a function. In fact you can think of React Components as functions that produce UI. This works especially well for functional stateless components, but if you squint, it works for pure stateful presentational components as well. A HOC is exactly a higher order function.

它是“高阶函数”,与“高阶函数”相同,后者是构建函数的函数。 实际上,您可以将React Components视为产生UI的函数。 这对于功能性无状态组件特别有效,但是,如果斜视,它也适用于纯有状态的表示组件。 HOC恰好是一个高阶函数。

HOC的例子 (Examples of HOCs)

There are many, but some notable ones:

有很多,但值得注意的是:

  • The most common is probably Redux’s connect function, which our buildReduxContainer function above is just a shabby version of.

    最常见的可能是Redux的 connect函数,我们上面的buildReduxContainer函数只是其简陋的版本。

  • React Router’s withRouter function which simply grabs the router off the context and makes it a prop for the child.

    React Router的 withRouter函数可以简单地将路由器从上下文中分离出来,并使其成为孩子的道具。

  • react-apollo's main interface is the graphql HOC, which, given a component and a GraphQL query, provides the results of that query to the child.

    react-apollo的主界面是graphql HOC,在给定组件和GraphQL查询的情况下,它将向子项提供该查询的结果。

  • Recompose is a library that’s full of HOCs that do a variety of small tasks you may want to abstract away from your components.

    Recompose是一个充满HOC的库,这些HOC可以执行您可能希望从组件中抽象出来的各种小任务。

定制HOC (Custom HOCs)

Should you write new HOCs in your app? Sure, if you have component patterns that could be generalized.

您是否应该在应用中编写新的HOC? 当然,如果您有可以概括的组件模式。

Beyond simply sharing utility libraries and simple composition, HOCs are the best way to share behavior between React Components.
除了简单地共享实用程序库和简单的组合之外,HOC是在React组件之间共享行为的最佳方法。

Writing a HOC is as simple as a function that returns a Class, like we saw with our buildReduxContainer function above. If you want to read more about what you can do when you build HOCs, I suggest you read Fran Guijarro’s extremely comprehensive post on the subject.

编写HOC就像返回类的函数一样简单,就像我们在上面的buildReduxContainer函数中看到的buildReduxContainer 。 如果您想了解有关构建HOC的更多信息,建议您阅读Fran Guijarro关于该主题的极为全面的文章

结论 (Conclusion)

Higher order components are at heart a codification of a separation of concerns in components in a functional way. Early versions of React used classes and mixins to achieve code reuse, but all signs point to this more functional approach driving the future design of React.

高阶组件本质上是以功能方式将组件中关注点分离的代码 。 早期版本的React使用类和mixin来实现代码重用,但是所有迹象都表明,这种更具功能性的方法推动了React的未来设计。

If your eyes typically glaze over when you hear about functional programming techniques, don’t worry! The React team has done a great job of taking the best simplifying parts of these approaches to lead us all toward writing more modular, componentized UIs.

如果在听到有关函数式编程技术的消息时,通常您的眼睛都呆滞了,那就不用担心! React团队在采用这些方法中最好的简化部分方面做得很出色,从而带领我们所有人编写更加模块化,组件化的UI。

If you want to learn more about building applications in a modern, component-oriented fashion, check my series of posts at Chroma, and if you like this article, please consider ?ing and sharing it!

如果您想了解有关以现代的,面向组件的方式构建应用程序的更多信息,请查看我在Chroma 上发表的系列文章 ,如果您喜欢本文,请考虑阅读并分享!

翻译自: https://www.freecodecamp.org/news/understanding-higher-order-components-6ce359d761b/

组件和高阶组件区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值