在React应用程序中拥有服务

我来自一个有角度的世界,在那里我可以将逻辑提取到服务/工厂,并在控制器中使用它们。

我试图了解如何在React应用程序中实现相同的目标。

假设我有一个可以验证用户密码输入(强度)的组件。它的逻辑非常复杂,因此我不想将其编写在自己的组件中。

我应该在哪里写这个逻辑?在商店中是否使用助焊剂?还是有更好的选择?

HarryItachi蛋蛋2020/03/11 14:59:39

我和你一样穿着靴子。在您提到的情况下,我会将输入验证UI组件实现为React组件。

我同意验证逻辑本身的实现不应(必须)耦合。因此,我将其放入单独的JS模块中。

也就是说,对于不应耦合的逻辑,请使用单独文件中的JS模块/类,并使用require / import将组件与“服务”分离。

这允许依赖项注入和两者的单元测试独立。

HarryL2020/03/11 14:59:39

同样的情况:完成了多个Angular项目并转移到React,没有一种简单的方法可以通过DI提供服务似乎缺少了一点(除了服务的细节)。

使用上下文和ES7 decorator,我们可以接近:

https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/

似乎这些家伙已经朝着另一个方向迈出了一步:

http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs

仍然感觉像在对抗谷物。在进行重大React项目后的6个月内,将重新讨论该答案。

编辑:6个月后,有了更多的React经验。考虑一下逻辑的性质:

  1. 它是否(仅)绑定到UI?将其移动到组件中(可接受的答案)。
  2. 它是否(仅)与状态管理联系在一起?将其移动到一个大块
  3. 绑在一起?移至单独的文件,通过选择器在组件中使用,并进行转换。

有些还可以重用HOC,但对我来说,以上内容涵盖了几乎所有用例。另外,请考虑使用鸭子扩展状态管理,以使关注点分离并以用户界面为中心。

凯Harry2020/03/11 14:59:39

请记住,React的目的是更好地耦合逻辑上应该耦合的事物。如果您要设计一个复杂的“验证密码”方法,应该在哪里使用?

那么,您将需要在每次用户需要输入新密码时使用它。这可以在注册屏幕,“忘记密码”屏幕,管理员“为另一个用户重置密码”屏幕等上。

但是在任何一种情况下,它总是与某些文本输入字段相关联。这就是应该将其耦合的地方。

制作一个非常小的React组件,该组件仅由输入字段和关联的验证逻辑组成。在所有可能需要输入密码的表单中输入该组件。

这与为逻辑提供服务/工厂实质上是相同的结果,但是您将其直接耦合到输入。因此,由于它永久地绑定在一起,因此您现在无需告诉该函数在哪里查找其验证输入。

西门十三LEY2020/03/11 14:59:38

当您意识到Angular服务只是一个提供一组上下文无关方法的对象时,问题变得非常简单。只是Angular DI机制使它看起来更加复杂。DI非常有用,因为它可以为您创建和维护实例,但您实际上并不需要它。

考虑一个流行的AJAX库axios(您可能已经听说过):

import axios from "axios";
axios.post(...);

它不是服务吗?它提供了一组负责某些特定逻辑的方法,并且独立于主代码。

您的示例案例是关于创建一组隔离的方法来验证您的输入(例如,检查密码强度)。有些人建议将这些方法放在组件中,这对我来说显然是一种反模式。如果验证涉及进行和处理XHR后端调用或进行复杂的计算该怎么办?您会将这种逻辑与鼠标单击处理程序和其他特定于UI的东西混合使用吗?废话。与容器/ HOC方法相同。包装您的组件只是为了添加一种方法,该方法将检查值中是否包含数字?来吧。

我将创建一个名为“ ValidationService.js”的新文件,并将其组织如下:

const ValidationService = {
    firstValidationMethod: function(value) {
        //inspect the value
    },

    secondValidationMethod: function(value) {
        //inspect the value
    }
};

export default ValidationService;

然后在您的组件中:

import ValidationService from "./services/ValidationService.js";

...

//inside the component
yourInputChangeHandler(event) {

    if(!ValidationService.firstValidationMethod(event.target.value) {
        //show a validation warning
        return false;
    }
    //proceed
}

您可以在任何地方使用此服务。如果验证规则更改,则只需要关注ValidationService.js文件。

You may need a more complicated service which depends on other services. In this case your service file may return a class constructor instead of a static object so you can create an instance of the object by yourself in the component. You may also consider implementing a simple singleton for making sure that there is always only one instance of the service object in use across the entire application.