基于react 来源的项目_feature-u(基于特征的React项目组织)

基于react 来源的项目

by Kevin Bridges

凯文·布里奇斯(Kevin Bridges)

feature-u :(基于功能的React项目组织) (feature-u: (Feature Based Project Organization for React))

This article is an introduction to feature-u — a library that facilitates feature-based project organization in your react project. This utility assists in organizing your project by individual features.

本文是对feature-u的介绍,它是一个 在您的React项目中促进基于功能的项目组织 。 该实用程序可帮助您按单个功能组织项目。

Most developers would agree that organizing your project by features is much preferred over type-based patterns. Because application domains grow in the real world, project organization by type simply doesn’t scale, it just becomes unmanageable!

大多数开发人员都会同意,与基于类型的模式相比,按功能组织项目是更可取的。 由于应用程序领域在现实世界中不断增长按类型组织的项目组织根本无法扩展,因此变得难以管理!

There are many good articles on this topic with insights on feature-based design and structure (see: References below).

关于此主题的很多好文章都对基于功能的设计和结构有深入的见解(请参阅下面的参考资料 )。

This article outlines my excursion into feature-based composition. In working through the details, I realized there was an opportunity for a library to help manage and streamline some of the hurdles incurred in this process. The result: feature-u (check out the full docs, GitHub source, and NPM package).

本文概述了我对基于特征的合成的游览。 通过细化细节,我意识到图书馆有机会帮助管理和简化此过程中遇到的一些障碍。 结果: feature-u (查看完整的docsGitHub源NPM软件包 )。

Update: On 8/14/2018 feature-u V1 was released, that re-designed Cross Feature Communication new to include UI Composition new as a core offering. A new article can be found here that takes a comprehensive approach in introducing you to all of feature-u (including V1). We are very excited about this update, because it promotes one solution for all feature collaboration! While upgrading to V1 requires some client code mods (see V1 Migration Notes), it is well worth it. This article is based on feature-u V0, and is using some antiquated APIs (mostly Feature.publicFace, and the app object). Still, this is a good resource to get your feet wet with feature-u.

更新 :在2018年8月14日发布了功能-u V1 ,该功能重新设计了new功能通信,以将UI构成new作为核心产品。 此处可以找到一篇新文章 ,该文章采用了一种全面的方法来向您介绍所有功能-u (包括V1 )。 我们对此更新感到非常兴奋,因为它为所有功能协作提供了一种解决方案 ! 升级到V1需要一些客户端代码mod(请参阅V1迁移说明 ),这是非常值得的。 本文基于feature-u V0 ,并使用了一些过时的API(主要是Feature.publicFaceapp对象)。 尽管如此,这还是一个很好的资源,您可以使用feature-u来弄湿自己。

乍看上去 (At a Glance)

Backdrop — why feature-u was created

背景 -为什么创建feature-u

feature-u Basics — introduce high-level feature-u concepts

Feature-U基础知识 —引入高级Feature-U概念

eatery-nod App — the sample app used to demonstrate feature-u

eatery-nod应用程序 —用于演示功能u的示例应用程序

Before & Aftereatery-nod project structure before and after features

之前和之后 —特色之前和之后的食堂项目结构

feature-u In Action — explore feature-u aspects through concrete examples

Feature-u在行动中 -通过具体示例探索Feature-U方面

feature-u Benefits — in summary

feature-u的好处 —总结

References — feature-based articles

参考 -基于功能的文章

背景 (Backdrop)

Let’s start by chronicling my journey in this process

让我们从开始记录这个过程开始

走出起跑门…… (out of the Starting Gate …)

Sooo … I had decided to restructure my project by features. From a design perspective, there were a number of considerations in determining the feature boundaries. I had read all the articles, and applied my design to a new feature-based directory structure.

如此...我决定通过功能重组我的项目 。 从设计的角度来看,在确定特征边界时需要考虑许多因素。 我已经阅读了所有文章,并将我的设计应用于新的基于功能的目录结构。

In general, I was feeling good about my progress. I was starting to see concrete benefits … feature segregation was going to result in code that is much more manageable!

总的来说,我对自己的进步感觉很好。 我开始看到具体的好处… 功能隔离将导致代码更易于管理!

障碍... (the Hurdles …)

However, there were a number of hurdles yet to be resolved …

但是,仍有许多障碍需要解决……

How can I encapsulate and isolate my features, while still allowing them to collaborate with one another?

如何封装和隔离我的功能,同时又允许它们相互协作?

How can selected features introduce start-up initialization (even injecting utility at the root DOM), without relying on some external startup process?

所选功能如何在不依赖某些外部启动过程的情况下,启动启动初始化(甚至在根DOM处注入工具)?

How can I promote feature-based UI components in an isolated and autonomous way?

如何以隔离和自主的方式提升基于功能的UI组件?

How can I configure my chosen frameworks now that my code is so spread out?

既然我的代码是如此分散,如何配置所选的框架?

How can I enable/disable selected features which are either optional, or require a license upgrade?

如何启用/禁用可选功能,这些功能要么是可选的,要么需要许可证升级?

In short, how can I pull it all together so that my individual features operate as one application?

简而言之,如何将所有功能组合在一起,以便我的单个功能可以作为一个应用程序运行?

目标(现在是什么?) (the Goal (what now?))

The overriding goal of feature-u is two-fold:

功能-u的首要目标有两个:

  1. Allow features to Plug-and-Play! This encompasses many things, such as: encapsulation, cross communication, enablement, initialization, and so on. We will build on these concepts throughout this article.

    允许功能即插即用! 这包含许多内容,例如:封装,交叉通信,启用,初始化等等。 在本文中,我们将基于这些概念。

  2. Automate the startup of your application!! You have the features. Allow them to promote their characteristics, so a central utility can automatically configure the frameworks used in your app, thereby launching your application. This task must be accomplished in an extendable way, because not everyone uses the same set of frameworks.

    自动启动您的应用程序! 您具有功能。 允许他们提升自己的特性,以便中央实用程序可以自动配置应用程序中使用的框架,从而启动您的应用程序。 此任务必须以可扩展的方式完成,因为并非每个人都使用同一组框架。

功能-u基础 (feature-u Basics)

The basic process of feature-u is that each feature promotes a Feature object that contains various aspects of that feature — things like the feature's name, its Public API, whether it is enabled, initialization constructs, and resources used to configure its slice of the frameworks in use.

功能-u的基本过程是,每个功能都会提升一个功能对象,该对象包含该功能的各个方面-诸如功能名称,其公共API,是否启用,初始化构造以及用于配置其功能的资源。使用中的框架。

In turn, these Feature objects are supplied to launchApp(), which configures and starts your application running. In addition, the returned App object is exported, in order to promote the public API of each feature.

反过来,这些Feature对象提供给launchApp() ,后者配置并启动应用程序的运行。 另外,导出的App对象将被导出,以提升每个功能的公共API。

方面 (aspects)

In feature-u, “aspect” is a generalized term used to refer to the various ingredients that (when combined) constitute your application.

在功能u中,“长宽比”是一个广义术语,用于指代(组合时)构成您的应用程序的各种成分。

Aspects can take on many different forms:

方面可以采取许多不同的形式:

  • UI Components and Routes

    UI组件和路线
  • State Management (actions, reducers, selectors)

    状态管理(动作,减速器,选择器)
  • Business Logic

    商业逻辑
  • Startup Initialization Code

    启动初始化代码
  • And so on…

    等等…

Not all aspects are of interest to feature-u — only those that are needed to setup and launch the app — all others are considered an internal implementation detail of the feature.

并非功能-u感兴趣的所有方面—仅是设置和启动应用所需的方面–所有其他方面均被视为功能的内部实现细节。

As an example, consider the redux state manager. While it uses actions, reducers, and selectors … only reducers are needed to setup and configure redux.

作为示例,考虑redux状态管理器。 当它使用动作,缩减器和选择器时…只需缩减器即可设置和配置redux。

框架整合 (framework integration)

A fundamental goal of feature-u is to automatically configure the framework(s) used in your run-time-stack (by accumulating the necessary resources across all your features). Because not everyone uses the same frameworks, feature-u accomplishes this through Extendable Aspects (you can find them in external NPM packages, or you can create your own).

功能-u的基本目标是自动配置运行时堆栈中使用的框架 (通过在所有功能上累积必要的资源)。 因为并非每个人都使用相同的框架,所以Feature-u通过可扩展方面 (您可以在外部NPM包中找到它们,也可以创建自己的)来实现此目的。

It is important to understand that the interface to your chosen frameworks is not altered in any way. You use them the same way you always have (just within your feature boundary).

重要的是要了解,所选框架的接口不会以任何方式改变。 您可以使用它们始终使用的方式(仅在要素边界内)使用它们。

feature-u merely provides a well defined organizational layer, where the frameworks are automatically setup and configured by accumulating the necessary resources across all your features.

feature-u仅提供一个定义明确的组织层,在该层中,通过在所有功能上累积必要的资源来自动设置和配置框架。

小食点应用 (eatery-nod App)

eatery-nod is the application where feature-u was conceived. It is a react-native expo mobile app, and is one of my sandbox applications that I use to test frameworks. I like to develop apps that I can use, but have enough real-world requirements to make it interesting.

eatery-nod是构思功能-u的应用程序。 这是一个本机 博览会移动应用程序,并且是我用来测试框架的沙箱应用程序之一。 我喜欢开发可以使用的应用程序,但对现实世界的要求足以使其有趣。

eatery-nod randomly selects a “date night” restaurant from a pool of favorites. My wife and I have a steady “date night”, and we are always indecisive on which of our favorite restaurants to frequent :-) So eatery-nod provides the spinning wheel!

eatery-nod从收藏夹中随机选择一个“约会之夜”餐厅。 我和我的妻子有一个稳定的“约会之夜”,我们总是对哪个我们最喜欢的餐厅经常光顾不定:-)因此,餐馆点头提供了转盘!

Take a look at the eatery-nod README to get a feel for the application. Screen flows are available, so it really helps in your orientation to the project.

看一看小餐馆的自述文件,以了解该应用程序。 屏幕流是可用的,因此它确实有助于您适应项目。

In addition, README files are found in each feature, describing what each feature accomplishes. Take some time now and skim through these resources:

此外,在每个功能中都可以找到自述文件 ,以描述每个功能的完成情况。 现在花点时间浏览这些资源:

  • device — initializes the device for use by the app, and promotes a device API abstraction

    设备 —初始化设备以供应用使用,并提升设备API抽象

  • auth — promotes complete user authentication

    认证 -促进完整的用户身份验证

  • leftNav — promotes the app-specific Drawer/SideBar on the app’s left side

    leftNav —在应用程序的左侧提升特定于应用程序的Drawer / SideBar

  • currentView — maintains the currentView with get/set cross-feature communication bindings

    目前看来 —通过获取/设置跨功能通信绑定维护currentView

  • eateries — manages and promotes the eateries view

    餐馆 -管理和推广餐厅视图

  • discovery — manages and promotes the discovery view

    发现 -管理和提升发现视图

  • firebase — initializes the Google Firebase service

    火力基地 —初始化Google Firebase服务

  • logActions — logs all dispatched actions and resulting state

    logActions —记录所有调度的动作和结果状态

  • sandbox — promotes a variety of interactive tests, used in development, that can easily be disabled

    沙盒 -促进开发中使用的各种交互式测试,这些测试很容易被禁用

之前和之后 (Before & After)

Anyone who knows me will tell you that I have an appreciation for a good before/after analysis. Whether it is a home remodel or a software refactor, it helps to chronicle where you have been, so as to quantify concrete achievements, and gives you a sense of accomplishment.

任何认识我的人都会告诉您,我对分析之前/之后的分析表示赞赏。 无论是家庭装修还是软件重构,它都可以帮助您编目您去过的地方,以量化具体成就,并给您成就感。

Let’s take a look at eatery-nod’s directory structure (before/after).

让我们看一下eatery-nod的目录结构(之前/之后)。

For illustration purposes, I have only expanded a few directories, but I think you get the idea.

出于说明目的,我仅扩展了几个目录,但我认为您明白了。

Before: here is my project's before features

之前 :这是我项目的之前功能 ...

eatery-nod src BEFORE featuressrc/├──actions/        ... redux actions│     auth.js│     discovery.js│     eateries.js│     ... snip snip├──api/            ... various abstract APIs│     device.js│     discovery.js│     ... snip snip├──app/            ... mainline startup **1**│  │  ScreenRouter.js│  │  SideBar.js│  │  index.js│  └──startup/│     │  createAppStore.js│     │  platformSetup.android.js│     │  platformSetup.ios.js│     └──firebase/│           firebaseAppConfig.js│           initFireBase.js├──appState/       ... redux reducers│     auth.js│     discovery.js│     eateries.js│     ... snip snip├──comp/           ... UI Component Screens│     DiscoveryListScreen.js│     EateriesListScreen.js│     ... snip snip├──logic/          ... redux-logic modules│     auth.js│     discovery.js│     eateries.js│     ... snip snip└──util/           ... common utilities

After: and here is the same project's after features

After :这是同一项目的after功能 ...

eatery-nod src AFTER featuressrc/│  app.js          ... launches app via launchApp() **2**├──feature/│  │  index.js     ... accumulate/promote all app Feature objects│  ├──auth/        ... the app's authorization feature│  │  │  actions.js│  │  │  featureName.js│  │  │  index.js│  │  │  logic.js│  │  │  publicFace.js│  │  │  route.js│  │  │  signInFormMeta.js│  │  │  state.js│  │  └──comp/│  │        SignInScreen.js│  │        SignInVerifyScreen.js│  ├──currentView/ ... other features│  ├──device/      ... feature to initialize the device│  │  │  actions.js│  │  │  api.js│  │  │  appDidStart.js│  │  │  appWillStart.js│  │  │  featureName.js│  │  │  index.js│  │  │  logic.js│  │  │  publicFace.js│  │  │  route.js│  │  │  state.js│  │  └──init/│  │        platformSetup.android.js│  │        platformSetup.ios.js│  ├──discovery/   ... more features│  ├──eateries/│  ├──firebase/│  ├──leftNav/│  ├──logActions/│  └──sandbox/└──util/           ... common utilities used across all features

As expected, the difference in project organization is dramatic!

不出所料,项目组织的差异是巨大的!

  • Before features — you find constructs for a given feature spread over numerous typed directories.

    在特征之前—找到分布在众多类型目录中的给定特征的构造。

  • After features: all aspects of a given feature are contained in its own isolated directory.

    功能之后 :给定功能的所有方面都包含在其自己的隔离目录中。

  • A notable difference is the dramatic reduction in complexity of the application startup process! The “before features” contained an entire app\ directory of startup code (see **1** above), while the "after features" simply contains a single app.js startup file (see **2** above). Where did all the complexity go? ... stay tuned!

    一个显着的区别是应用程序启动过程的复杂性大大降低了! “ before features”包含整个启动目录的app\目录(请参见上面的**1** ),而“ before features”仅包含一个app.js启动文件(请参见上面的**2** )。 所有的复杂性都去了哪里? ... 敬请关注!

feature-u实际使用中 (feature-u In Action)

To better understand feature-u, let’s take a closer look at some eatery-nod examples in action.

为了更好地理解功能-u,让我们仔细看一些实际的“食堂点头”示例。

Each of the following sections briefly introduce a new feature-u topic, correlating sample code from eatery-nod. Additional information is provided through links, both to the feature-u docs, and eatery-nod source code. In some cases the in-lined sample code has been streamlined (to emphasize a focal point), however the caption link will take you to the actual code (hosted on GitHub).

以下各节简要介绍了一个新的feature-u主题,该主题将来自eatery-nod的示例代码相关联。 通过指向feature-u文档和eatery-nod源代码的链接提供了其他信息。 在某些情况下,已简化了内联示例代码(以强调重点),但是标题链接会将您带到实际代码(托管在GitHub上)。

Here are our topics …

这是我们的主题...

  1. Simplified App Startup

    简化的应用启动

  2. React Platforms

    React平台

  3. Feature Object

    特征对象

  4. Feature Initialization

    功能初始化

  5. Feature Collaboration

    功能协作

  6. Framework Integration

    框架整合

  7. Feature Enablement

    功能启用

  8. Managed Code Expansion

    托管代码扩展

  9. UI Component Promotion

    UI组件升级

  10. Single Source of Truth

    真理的单一来源

1.简化的应用启动 (1. Simplified App Startup)

After breaking your application up into pieces (as with features), how do you pull them all back together, and actually start your app running? At first glance, this may seem like a daunting task. As it turns out, however, because of the structure promoted by feature-u, it actually is a very simple process.

将应用程序分解为多个部分(与功能一起)后,如何将它们重新组合在一起,并真正开始运行应用程序? 乍一看,这似乎是一项艰巨的任务。 然而,事实证明,由于功能-u促进了结构,它实际上是一个非常简单的过程。

To solve this, feature-u provides the launchApp() function (see: Launching Your Application).

为了解决这个问题,功能-u提供了launchApp()函数(请参阅: 启动应用程序 )。

Here is eatery-nod’s mainline …

这是小餐馆点的主线…

The first thing to note is just how simple and generic the mainline startup process is. There is no real app-specific code in it … not even any global initialization!

首先要注意的是,主线启动过程是如此简单和通用。 其中没有真正的应用特定代码……甚至没有任何全局初始化!

That is because feature-u provides various hooks that allow your features to inject their own app-specific constructs.

这是因为feature-u提供了各种钩子,这些钩子使您的功能可以注入自己的特定于应用程序的结构。

The mainline merely accumulates the Aspects and Features, and starts the app by invoking launchApp().

主线仅累积方面和功能,并通过调用launchApp()启动应用程序。

Here are some important points of interest (match the numbers to *n* in the code above):

这里是一些重要的兴趣点(将上面的代码中的*n*与数字匹配):

  1. (*1*) the supplied Aspects (pulled from separate NPM packages) reflect the frameworks of our run-time stack (in our example redux, redux-logic, and feature-router) and extend the acceptable Feature properties — Feature.reducer, Feature.logic, and Feature.route respectively. (See Extendable aspects).

    ( *1* )所提供的各方面(从分开的NPM包拉动)反映我们运行时间堆栈的框架(在我们的例子reduxredux-logic ,和feature-router )和延伸可接受功能属性- Feature.reducerFeature.logicFeature.route 。 (请参阅可扩展方面 )。

  2. (*2*)all app features are accumulated from our feature/ directory

    ( *2* )所有应用程序功能都是从我们的feature/目录中累积的

  3. (*3*)as a preview to Feature Collaboration, the exported return value of launchApp() is an App object, which promotes the accumulated Public API of all features.

    ( *3* )作为Feature Collaboration的预览, launchApp()的导出返回值是一个App对象,它促进所有功能的累积Public API。

2. React平台 (2. React Platforms)

In the example above (see *4*), you see that launchApp() uses a registerRootAppElm() callback hook to register the supplied rootAppElm to the specific React platform in use. Because this registration is accomplished by app-specific code, feature-u can operate in any of the React platforms (see React Registration).

在上面的示例中(请参阅*4* ),您可以看到launchApp()使用registerRootAppElm()回调钩子将提供的rootAppElm注册到正在使用的特定React平台上。 由于此注册是通过特定于应用程序的代码完成的,因此feature-u可以在任何React平台上运行(请参见React Registration )。

Here are some registerRootAppElm() variations:

这是一些registerRootAppElm()变体:

react web:

React网站

react-native:

React本机

expo:

博览会

3.特征对象 (3. Feature Object)

Each feature is located in its own directory, and promotes aspect content through a Feature object (using createFeature()).

每个功能都位于其自己的目录中,并通过Feature对象(使用createFeature() )来提升方面内容。

Here is an example from eatery-nod’s device feature.

这是来自eatery-nod的设备功能的示例。

As you can see, the Feature object is merely a container that holds aspect content of interest to feature-u. The sole purpose of the Feature object is to communicate this aspect information to launchApp().

如您所见, Feature对象仅仅是一个容器,其中包含feature-u感兴趣的方面内容。 Feature对象的唯一目的是将该方面信息传达给launchApp()

We will fill in more detail a bit later, but for now notice that the feature is conveying reducers, logic modules, routes, and does some type of initialization (appWillStart/appDidStart). It also promotes a publicFace that can be used by other features (such as the feature’s Public API).

稍后我们将更详细地填写,但现在请注意,该功能正在传递减速器,逻辑模块,路线并进行某种类型的初始化( appWillStart / appDidStart )。 它还促进了可由其他功能(例如,功能的Public API)使用的publicFace

For more information, please refer to Feature & aspect content.

有关更多信息,请参阅功能和外观内容

4.功能初始化 (4. Feature Initialization)

Any given feature should not have to rely on an external startup process to perform the initialization that it needs. Rather, the feature should be able to spawn initialization that it depends on.

任何给定的功能都不必依赖外部启动过程来执行所需的初始化。 而是,该功能应该能够产生它所依赖的初始化。

This could be any number of things, such as:

这可以是任何数目的事物,例如:

  • initialize some service API

    初始化一些服务API
  • inject a utility react component at the App root

    在应用程序根目录注入实用程序react组件
  • dispatch an action that kicks off a startup process

    调度启动启动过程的操作
  • And more...

    和更多...

To solve this, feature-u introduces two Application Life Cycle Hooks, injected through the following Feature aspects:

为了解决这个问题,feature-u引入了两个Application Life Cycle Hook ,它们通过以下Feature方面注入:

  1. Feature.appWillStart({app, curRootAppElm}): rootAppElm || falsy Invoked one time, just before the app starts up. This can do any type of initialization, including supplementing the app's top-level root element (such as the React component instance).

    Feature.appWillStart({app, curRootAppElm}): rootAppElm || falsy Feature.appWillStart({app, curRootAppElm}): rootAppElm || falsy在应用程序启动之前调用了一次。 这可以执行任何类型的初始化,包括补充应用程序的顶级根元素(例如React component实例)。

  2. Feature.appDidStart({app, appState, dispatch}): void

    Feature.appDidStart({app, appState, dispatch}): void

    Invoked one time immediately after the app has started. A typical usage for this hook is to dispatch some type of

    应用启动后立即调用一次。 这个钩子的典型用法是调度某种类型的

    bootstrap action.

    bootstrap action

Here are some examples from eatery-nod:

以下是来自小餐馆点头的一些示例:

FireBase Initialization:

FireBase初始化:

Bootstrap Action:

引导动作:

Inject DOM Root Elm:

注入DOM根榆木:

5.功能协作 (5. Feature Collaboration)

Even though a feature’s implementation is encapsulated, it still needs to interact with its surroundings. To complicate matters, one feature should never import resources from another feature, because it should strive to be plug-and-play. As a result, we need a well-defined feature-based Public API.

即使功能的实现被封装,它仍然需要与其周围环境进行交互。 使事情变得复杂的是,一个功能永远不要从另一功能导入资源,因为它应该努力做到即插即用。 因此,我们需要一个定义明确的基于功能的Public API。

To solve this, feature-u promotes a Cross Feature Communication. This is accomplished through the Feature.publicFaceBuilt-In aspect property. A feature can expose whatever it deems necessary through its publicFace. There are no real constraints on this resource. It is truly open.

为了解决这个问题,feature-u促进了跨功能通信 。 这是通过Feature.publicFace 内置方面属性完成的。 功能可以通过publicFace公开其认为必要的任何内容。 此资源没有实际限制。 它是真正开放的。

Typically this involves promoting selected:

通常,这涉及提升选定的内容:

  • actions

    行动
  • selectors

    选择器
  • APIs

    蜜蜂
  • And so on

    等等

The publicFace of all features are accumulated and exposed through the App object (emitted from launchApp()).

所有功能的publicFace都是通过App对象(从launchApp()发出launchApp()累积和公开的。

It contains named feature nodes, as follows:

它包含命名要素节点,如下所示:

App.{featureName}.{publicFace}

Here is an example from eatery-nod’s auth feature.

这是来自eatery-nod的auth功能的示例。

Out of all the items found in the auth feature, only two actions and one selector are public.

auth功能中找到的所有项目中,只有两个操作和一个选择器是公共的。

Here is what the App object would look like for this example:

此示例的App对象如下所示:

app: {  auth: {    actions: {      userProfileChanged(userProfile),      signOut(),    },    sel: {      getUserPool(appState),    },  },  currentView: {   // other features    ... snip snip  },}

As a result, the auth feature's public API can be accessed as follows:

结果,可以按以下方式访问auth功能的公共API:

app.auth.actions.userProfileChanged(userProfile)app.auth.actions.signOut()app.auth.sel.getUserPool(appState)

6.框架整合 (6. Framework Integration)

Most likely your application employs one or more frameworks (such as redux or redux-logic). How are the resources needed by these frameworks accumulated and configured across the many features of your app?

您的应用程序很可能采用一个或多个框架(例如reduxredux-logic )。 这些框架所需的资源如何在您的应用程序的许多功能中累积和配置?

To solve this, feature-u introduces Extendable aspects. feature-u is extendable. It provides integration points between your features and your chosen frameworks.

为了解决这个问题,feature-u引入了可扩展方面feature-u可扩展的 。 它提供了功能与所选框架之间的集成点。

Extendable Aspects are packaged separately from feature-u, so as to not introduce unwanted dependencies (because not everyone uses the same frameworks). You pick and choose them based on the framework(s) used in your project (matching your project’s run-time stack). They are created with feature-u’s extendable API, using createAspect(). You can define your own Aspect, if the one you need doesn't already exist.

可扩展方面与feature-u分开包装,以免引入不需要的依赖性(因为并非每个人都使用相同的框架)。 您可以根据项目中使用的框架(与项目的运行时堆栈匹配)进行选择。 它们是使用feature-u的可扩展API使用createAspect()创建的 。 如果您需要的方面还不存在,则可以定义自己的方面。

Let’s take a look at a redux example from eatery-nod.

让我们看一看来自eatery-nod的redux示例。

The device feature maintains its own slice of the state tree.

device功能部件维护其自己的状态树切片。

It promotes its reducer through the Feature.reducer aspect:

它通过Feature.reducer方面来提升其减速器:

Because Feature.reducer is an extended aspect (verses a built-in aspect), it is only available because we registered the feature-redux reducerAspect to launchApp() (please refer to Simplified App Startup above).

因为Feature.reducer是扩展方面(与内置方面reducerAspect ),所以仅当我们将feature-redux reducerAspect注册到launchApp()时才可用(请参阅上面的简化应用程序启动 )。

The key thing to understand is that feature-u (through the feature-redux extension) will automatically configure redux by accumulating all feature reducers into one overall appState.

要了解的关键是,feature-u(通过feature-redux扩展名)将通过将所有功能简化器累积到一个整体appState中来自动配置redux。

Here is the reducer code …

这是减速器代码……

A feature-based reducer is simply a normal reducer that manages the feature’s slice of the the overall appState. The only difference is it must be embellished with slicedReducer(), which provides instructions on where to insert it in the overall top-level appState.

基于功能的简化器只是管理整个appState的功能部分的普通简化器。 唯一的区别是,必须使用slicedReducer()对其进行修饰,该slicedReducer()提供了有关将其插入整个顶级appState中的位置的说明。

As a result, the device reducer only maintains the state relevant to the device feature (like its little slice of the world) — a status, a fontsLoaded indicator, and the device location.

结果, device精简器仅维护与device功能相关的状态(例如其一小部分),即状态,fontsLoaded指示器和设备位置。

SideBar: We are using the astx-redux-util utility’s reducerHash() function to concisely implement the feature's reducer (providing an alternative to the common switch statement). I have found that in using a utility like this, for most cases it is feasible to implement all the reducers of a feature in one file (due in part to the smaller boundary of a feature). astx-redux-util also promotes other Higher-Order Reducers. You may want to check this out.

边栏 :我们正在使用astx-redux-util实用程序的reducerHash()函数来简洁地实现该功能的reducer(提供了通用switch语句的替代方法)。 我发现在使用这样的实用程序时,在大多数情况下,在一个文件中实现某个功能的所有简化工具是可行的(部分原因是某个功能的边界较小)。 astx-redux-util也可以推广其他High- Order Reducer 。 您可能要检查一下。

7.功能启用 (7. Feature Enablement)

Some of your features may need to be dynamically enabled or disabled. As an example, certain features may only be enabled with a license upgrade, or other features may only be used for diagnostic purposes.

您的某些功能可能需要动态启用或禁用。 例如,某些功能只能通过许可证升级来启用,或者其他功能只能用于诊断目的。

To solve this, feature-u introduces Feature Enablement. Using the Feature.enabled Built-In aspect (a boolean property), you can enable or disable your feature.

为了解决这个问题,feature-u引入了Feature Enablement 。 使用Feature.enabled内置方面(布尔属性),可以启用或禁用功能。

Here is an example from eatery-nod’s sandbox feature:

这是来自eatery-nod 沙盒功能的示例:

The sandbox feature promotes a variety of interactive tests, used in development, that can easily be disabled.

沙盒功能可促进开发中使用的各种交互式测试,这些测试很容易被禁用。

Typically this indicator is based on a dynamic expression, but in this case it is simply hard-coded (to be set by a developer).

通常,该指示器基于动态表达式,但是在这种情况下,它只是经过硬编码(由开发人员设置)。

SideBar: When other features interact with a feature that can be disabled, you can use the App object to determine if a feature is present or not (see: Feature Enablement for more information).

边栏 :当其他功能与可以禁用的功能进行交互时,可以使用App对象确定是否存在某个功能(有关更多信息,请参见: 功能启用 )。

8.托管代码扩展 (8. Managed Code Expansion)

In general, accessing imported resources during in-line code expansion can be problematic, due to the order in which these resources are expanded. The feature-u App object is such a critical resource (because it promotes the Public API of all features), it must be available even during code expansion. In other words, we cannot rely on an "imported app" being resolved during code expansion time.

通常,由于扩展这些资源的顺序,因此在嵌入式代码扩展过程中访问导入的资源可能会出现问题。 功能-u App对象是如此重要的资源(因为它促进了所有功能的Public API), 因此即使在代码扩展期间它也必须可用 。 换句话说,我们不能依靠在代码扩展期间解析“导入的应用程序”。

To solve this, feature-u introduces Managed Code Expansion.

为了解决这个问题,feature-u引入了托管代码扩展

When aspect content definitions require the App object at code expansion time, you simply wrap the definition in a managedExpansion() function. In other words, your aspect content can either be the actual content itself (such as a reducer), or a function that returns the content.

当方面内容定义在代码扩展时需要App对象时,只需将定义包装在managedExpansion()函数中即可。 换句话说,方面内容可以是实际的内容本身(例如reducer),也可以是返回内容的函数。

When this is done, feature-u will expand it by invoking it in a controlled way, passing the fully resolved App object as a parameter.

完成此操作后,feature-u将通过以受控方式调用它来扩展它,并将完全解析的App对象作为参数传递。

Here is a logic module from eatery-nod’s auth feature:

这是来自eatery-nod的auth功能的逻辑模块:

You can see that the auth feature is using an action from the device feature, requiring access to the app object (see *2*). Because the app object is needed during code expansion, we use the managedExpansion() function (see *1*), allowing feature-u to expand it in a controlled way, passing the fully resolved app object as a parameter.

您可以看到auth功能正在使用设备功能中的操作,需要访问app对象(请参阅*2* )。 因为在代码扩展期间需要该app对象,所以我们使用managedExpansion()函数(请参阅*1* ),从而允许功能-u以受控方式扩展它,并将完全解析的app对象作为参数传递。

9. UI组件升级 (9. UI Component Promotion)

Features that maintain their own UI Components need a way to promote them in the overall app’s GUI. Because features are encapsulated, how is this accomplished in an autonomous way?

维护自己的UI组件的功能需要一种在整个应用程序的GUI中对其进行升级的方法。 因为功能是封装的,这如何以自主的方式完成?

To address this, feature-u recommends considering Feature Based Routes via the feature-router extendable Aspect (packaged separately). This approach can even be used in conjunction with other navigational solutions.

为了解决这个问题,feature-u建议通过Feature-Router可扩展的Aspect(单独包装)考虑基于Feature的路由 。 这种方法甚至可以与其他导航解决方案结合使用。

Feature Routes are based on a very simple concept: allow the application state to drive the routes! It operates through a series of feature-based routing functions that reason about the appState, and either return a rendered component, or null to allow downstream routes the same opportunity.

功能路由基于一个非常简单的概念:允许应用程序状态驱动路由! 它通过一系列基于功能的路由功能进行操作,这些路由功能会针对appState进行推理,并返回渲染的组件,或者返回null以允许下游路由具有相同的机会。

Here is a simple example from the device feature.

这是设备功能的一个简单示例。

This route analyzes the current appState, and displays a SplashScreen until the system is ready:

此路由分析当前的appState,并显示SplashScreen,直到系统准备就绪:

In feature based routing, you will not find the typical “route path to component” mapping catalog, where (for example) some pseudo route('device') directive causes the Device screen to display, which in turn causes the system to accommodate the request by adjusting its state appropriately.

在基于功能的路由中,您将找不到典型的“到组件的路由路径”映射目录,在该目录中(例如)某些伪route('device')伪指令导致显示route('device')屏幕,从而导致系统适应通过适当调整其状态来请求。

Rather, the appState is analyzed, and if the device is NOT ready, no other screens are given the option to even render ... Easy Peasy!

而是对appState进行分析,如果设备尚未就绪,则不会向其他屏幕提供甚至渲染的选项。

Depending on your perspective, this approach can be more natural, but more importantly, it allows features to promote their own screens in an encapsulated and autonomous way.

根据您的观点,此方法可能更自然,但更重要的是,它允许功能以封装的自主方式来提升自己的屏幕。

10.真理的单一来源 (10. Single Source of Truth)

Feature implementations (like all coding constructs) should strive to follow the single-source-of-truth principle. In doing this, a single line modification can propagate to many areas of your implementation.

功能实现(像所有编码构造一样)应努力遵循真实单一来源原则。 这样,单行修改可以传播到实现的许多区域。

What are some Best Practices for single-source-of-truth as it relates to features, and how can feature-u help?

与功能相关的单一真相的最佳做法是什么?feature-u如何提供帮助?

The Best Practices section highlights a number of feature-based single-source-of-truth items of interest. These are guidelines, because you must implement them in your application code (feature-u is not in control of this).

最佳实践”部分重点介绍了许多基于功能的单一事实真相。 这些是准则,因为您必须在应用程序代码中实现它们(feature-u对此不起作用)。

Here is an example from the eateries feature:

这是来自餐厅功能的示例:

The featureName is used to specify the top-level state location of this feature (see *1*). feature-u guarantees the feature name is unique. As a result, it can be used to qualify the identity of several feature aspects.

featureName用于指定此功能的顶级状态位置(请参阅*1* )。 feature-u保证功能名称是唯一的。 结果,它可以用来限定几个特征方面的身份。

For example:

例如:

  • prefix action types with featureName, guaranteeing their uniqueness app-wide (see: feature-redux docs)

    为动作类型添加featureName前缀,以确保其在应用程序范围内的唯一性(请参阅: feature-redux文档)

  • prefix logic module names with featureName, identifying where that module lives (see: feature-redux-logic docs)

    为逻辑模块名称添加一个featureName前缀,以标识该模块所在的位置(请参阅: feature-redux-logic docs)

  • depending on the context, the featureName can be used as the root of your feature state’s shape (see: feature-redux docs)

    根据上下文,featureName可以用作要素状态形状的根(请参阅: feature-redux docs)

Because feature-u relies on slicedReducer() (in the feature-redux package), a best practice is to use the reducer's embellished selector to qualify your feature state root in all your selector definitions. As a result the slice definition is maintained in one spot (see *2*).

因为feature-u依赖于slicedReducer() (在feature-redux包中),所以最佳实践是使用reducer修饰的选择器来限定所有选择器定义中的功能状态根。 结果,切片定义保持在一个位置(请参阅*2* )。

Feature-U的好处 (feature-u Benefits)

In summary, the benefits of using feature-u include:

总之,使用功能-u的好处包括:

  • Feature Encapsulation — isolating feature implementations improves code manageability

    功能封装 -隔离功能实现可提高代码可管理性

  • Cross Feature Communication — a feature’s public API is promoted through a well-defined standard

    跨功能通信 -通过明确定义的标准来促进功能的公共API

  • Feature Enablement — enable/disable features through a run-time switch

    功能启用 -通过运行时开关启用/禁用功能

  • Application Life Cycle Hooks — features can initialize themselves without relying on an external process

    应用程序生命周期挂钩 —功能可以自行初始化,而无需依赖外部进程

  • Single Source of Truth — is facilitated in a number of ways within a feature’s implementation

    真相的单一来源 -在功能实现中以多种方式得到促进

  • Framework Integration — configure the framework(s) of your choice (matching your run-time-stack) using feature-u’s extendable API

    框架集成 -使用Feature-U的可扩展API配置您选择的框架(与您的运行时堆栈匹配)

  • UI Component Promotion — through Feature Routes

    UI组件升级 —通过功能路线

  • Minimize Feature Order Dependency Issues — even in code that is expanded in-line

    最大限度地减少功能订单的依存关系问题 ,即使是在在线扩展的代码中

  • Plug-and-Play — features can be added/removed easily

    即插即用 -可以轻松添加/删除功能

  • Simplified Mainline launcApp() starts the app running by configuring the frameworks in use, all driven by a simple set of features.

    简化的主线launcApp()通过配置使用中的框架来启动应用程序运行,所有框架均由一组简单的功能驱动。

  • Operates in any React Platform (including React Web, React Native and Expo)

    可在任何React平台 (包括React Web,React Native和Expo)中运行

Hopefully this article gives you a feel for how feature-u can improve your project. Please refer to the full documentation for more details.

希望本文使您对Feature-u如何改善您的项目有一种感觉。 请参阅完整的文档以获取更多详细信息。

feature-u allows you to focus your attention on the “business end” of your features! Go forth and compute!!

feature-u使您可以将注意力集中在功能的“业务端”上! 继续计算!

参考文献 (References)

翻译自: https://www.freecodecamp.org/news/feature-u-cf3277b11318/

基于react 来源的项目

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值