React组件设计的新方法

by Austin Malerba

奥斯汀·马勒巴(Austin Malerba)

React组件设计的新方法 (A New Approach to React Component Design)

In 2015, Dan Abramov wrote an article, Presentational and Container Components, that some React new-comers misconstrued as commandments. In fact, I myself stumbled upon the article and many others echoing its teachings and I thought, this must be the best way to separate concerns amongst components.

2015年,Dan Abramov写了一篇文章Presentational and Container Components ,一些React新人误解为诫命。 实际上,我本人偶然发现了这篇文章,而许多其他文章也都赞同它的教义,我认为, 这一定是将关注点分离出来的最佳方法

But, Dan Abramov himself later addressed the community for clinging to the design patterns he outlined.

但是,丹·阿布拉莫夫(Dan Abramov)本人后来因坚持他概述的设计模式而向社区致辞。

In working with React for over a year now, I’ve stumbled into my own design patterns and here I will try to formalize them. Take these ideas with a grain of salt, they’re just my own observations that I have found constructive.

在与React一起工作了一年多的时间里,我偶然发现了自己的设计模式,在这里我将尝试对其进行形式化。 将这些想法付诸实践,只是我自己的发现,这些发现对我很有建设性。

逃避二分法 (Escaping the Dichotomy)

For a long time, components have been broadly classified as either smart or dumb, container or presentational, stateful or stateless, pure or impure. There’s a lot of terminology, but they all mean about the same thing. Smart components know how to tie together your application and dumb components just take in data to present to the end user. This is a useful distinction, but it’s really not how I find myself thinking while designing components.

长期以来,组件被广泛地分为智能或哑,容器或外观,有状态或无状态,纯或不纯。 有很多术语,但是它们都意味着同一件事。 智能组件知道如何将您的应用程序和哑组件捆绑在一起,只需将数据呈现给最终用户即可。 这是一个有用的区别,但实际上并不是我发现自己在设计组件时在想什么。

The problem with the Container vs Presentational mindset is that it tries too hard to define component responsibilities in terms of state, logic, and other aspects of a component’s inner-workings.

Container vs Presentational思维方式的问题在于,它很难根据状态,逻辑以及组件内部工作的其他方面来定义组件职责。

Component design is better approached by deferring the implementation details and thinking in terms of component interfaces. It’s particularly important to think about what kind of customizations a component should allow and what kind of implicit and explicit dependencies a component should include.

通过推迟实现细节和根据组件接口进行思考,可以更好地实现组件设计。 考虑组件应允许的自定义类型以及组件应包括的隐式和显式依赖项尤其重要。

介绍三分法 (Introducing the Trichotomy)

Trichotomy? Is that even a word? I don’t know, but you get the idea. I’ve come to think of React components as falling into one of three bins.

三分法? 这甚至是一个字吗? 我不知道,但是你明白了。 我开始认为React组件属于三个容器之一。

通用组件 (Universal Components)

These are components that can be used many times in any application.

这些组件可以在任何应用程序中多次使用

These components:

这些组成部分:

  • Should be reusable

    应该可重用

  • Should be highly customizable

    应该高度可定制

  • Should not be aware of application-specific code including models, stores, services, etc.

    不应了解特定于应用程序的代码,包括模型,商店,服务等。

  • Should minimize dependencies on third party libraries

    应该最小化对第三方库的依赖

  • Should rarely be used directly in your application

    很少应在您的应用程序中直接使用
  • Should be used as building blocks for Global components

    应该用作全局组件的构建基块

  • May end with the “Base” suffix (eg. ButtonBase, ImageBase)

    可能以“ Base”后缀结尾(例如ButtonBase,ImageBase)

These are foundational components that are application-agnostic and aren’t necessarily to be used directly in your View components because they are often too customizable. To use them directly in your View components would mean a lot of copying and pasting of the same boiler plate. You’d also risk developers abusing the components’ highly customizable nature in ways that create an inconsistent experience across your application.

这些是与应用程序无关的基础组件,不一定必须直接在您的View组件中使用,因为它们经常过于可定制。 直接在View组件中使用它们将意味着大量复制和粘贴同一样板。 您还冒着开发人员滥用组件高度可定制性的方式,从而在整个应用程序中产生不一致的体验。

全球组成 (Global Components)

These are components that can be used many times in one application.

这些组件可以在一个应用程序中多次使用

These components:

这些组成部分:

  • Should be reusable

    应该可重用

  • Should be minimally customizable

    应该是最小可定制的

  • May use application-specific code

    可以使用特定应用程序的代码

  • Should implement Universal components, restricting their customizability

    应该实现通用组件 ,限制其可定制性

  • Should be used as building blocks for View components

    应该用作View组件的构建块

  • Often tie one-to-one with model instances (eg. DogListItem, CatCard)

    通常与模型实例一对一联系(例如DogListItem,CatCard)

These components are reusable within your application but are not easily transferred to other applications because they depend on application logic. These are the building blocks for View components and other Global components.

这些组件可在您的应用程序中重用,但由于它们取决于应用程序逻辑,因此不容易转移到其他应用程序。 这些是View组件和其他Global组件的构建块。

They should be minimally customizable to ensure consistency across your application. Applications shouldn’t have thirty different button variations, but rather should have a handful of different button variations. This should be enforced by taking a highly customizable Universal ButtonBase component and baking into it styles and functionality in the form of a Global Button component. Global components often take another form as representations of domain model data.

它们应该是最小可定制的,以确保整个应用程序的一致性。 应用程序不应具有三十种不同的按钮变化,而应具有几种不同的按钮变化。 这应该通过采用高度可定制的Universal ButtonBase组件并以Global Button组件的形式融入其样式和功能中来实施。 全局组件通常采用另一种形式来表示域模型数据。

查看组件 (View Components)

These are components that are used only once in your application.

这些是在您的应用程序中仅使用一次的组件。

These components:

这些组成部分:

  • Should not be concerned about reusability

    应该担心可重用性

  • Are likely to manage state

    有可能管理状态

  • Receive minimal props

    获得最少的道具

  • Should tie together Global components (and possibly Universal components)

    应该将全局组件(可能还有通用组件)联系在一起
  • Often resolve application routes

    经常解决申请路线

  • Often maintain a dedicated plot of viewport real estate

    经常维护专用的视口房地产图
  • Often have a high number of dependencies

    经常有大量的依赖
  • Should be building blocks for your application

    应该是您的应用程序的构建基块

These are the highest level components of your application that glue together reusable components and even other Views. These will often be the components that resolve routes and may show in the form of page-level components. They are heavy in state and light in props. These are what Dan Abramov would consider container components.

这些是应用程序中最高级的组件,它们将可重用的组件甚至其他视图粘合在一起。 这些通常是解析路由的组件,并可能以页面级组件的形式显示。 他们状态沉重,道具轻巧。 这些是Dan Abramov将考虑的容器组件。

PromiseButton (The PromiseButton)

Let’s take a look at the Universal and Global implementations of a promise button and see how they compare. A promise button acts like an ordinary button unless the onClick handler returns a promise. In the case of a returned promise, the button can conditionally render content based on the promise state.

让我们看一下Promise按钮的Universal和Global实现,并比较它们的比较。 除非onClick处理程序返回诺言,否则诺言按钮的作用类似于普通按钮。 在返回承诺的情况下,按钮可以根据承诺状态有条件地呈现内容。

Notice how the PromiseButtonBase allows us to control what to render at any point in the promise life-cycle, but the PromiseButton bakes in the teal PulseLoader during the pending state. Now any time we use the PromiseButton, we’re guaranteed a teal loading animation and we don’t have to worry about duplicating that code or providing an inconsistent loading experience by including multiple loading animations of multiple colors across our application. The PromiseButtonBase is customizable, but the PromiseButton is restrictive.

注意PromiseButtonBase如何允许我们控制承诺生命周期中任何时刻的渲染,但是PromiseButton在挂起状态期间在蓝绿色PulseLoader中烘烤。 现在,每次使用PromiseButton时,我们都可以保证获得蓝绿色的加载动画,而不必担心通过在应用程序中包含多种颜色的多个加载动画来复制该代码或提供不一致的加载体验。 PromiseButtonBase是可自定义的,但是PromiseButton是限制性的。

目录结构 (Directory Structure)

The following illustrates how we might organize components following this pattern.

下面说明了如何按照这种模式组织组件。

App/
  App.js
  Views/
    DogListView/
  Global/
    Models/
      Dog/
        DogListItem/
    Image/
    PromiseButton/
Universal/
  ImageBase/
  PromiseButtonBase/
组件依赖性 (Component Dependencies)

Below illustrates how the above components depend on one another.

下面说明了上述组件如何相互依赖。

/* App.js */
import { DogListView } from './Views'

/* DogListView.js */
import { DogListItem } from 'App/Global/Models/Dog'

/* DogListItem.js */
import Image from '../../Image',
import PromiseButton from '../../PromiseButton'

/* Image.js */
import { ImageBase } from 'Universal'

/* PromiseButton.js */
import { PromiseButtonBase } from 'Universal'

Our View component depends on a Global component and our Global components depend on other Global components as well as Universal components. This dependency flow will be pretty common. Notice also the use of absolute and relative imports. It’s nice to use relative imports when pulling in dependencies that reside within the same module. Also, it’s nice to use absolute imports when pulling in dependencies across modules or when your directory structure is deeply nested or frequently changing.

我们的视图组件依赖于全局组件,而我们的全局组件则依赖于其他全局组件以及通用组件。 这种依赖关系流将非常普遍。 还请注意绝对和相对进口的使用。 引入驻留在同一模块中的依赖项时,最好使用相对导入。 另外,在跨模块引入依赖关系或目录结构被深嵌套或频繁更改时,最好使用绝对导入。

The problem with the Container vs Presentational model is that it tries too hard to define component responsibilities in terms of component inner-workings. The key takeaway is to view component design in terms of component interfaces. What matters less is the implementation that allows the component to satisfy its contract. It’s important to think about what kind of customizations a component should allow and what kind of implicit and explicit dependencies a component should include.

Container vs Presentational模型的问题在于,它很难尝试根据组件内部工作来定义组件职责。 重点是从组件接口的角度查看组件设计。 无关紧要的是允许组件履行其合同的实现。 考虑组件应允许的自定义类型以及组件应包括的隐式和显式依赖项非常重要。

If you’ve found these thoughts helpful and would like to see more of my ideas, feel free to check out this repo which I use to maintain my thoughts and best practices for writing React/Redux apps.

如果您认为这些想法有用,并且想了解我的更多想法,请随时查看此回购协议 ,该代码用于维护我的想法和编写React / Redux应用程序的最佳实践。

翻译自: https://www.freecodecamp.org/news/a-new-approach-to-react-component-design-2bf76a87add1/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值