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

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

假设我有一个验证用户密码输入的组件(它的强度)。它的逻辑相当复杂,因此我不想把它写在组件中。

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


当前回答

同样的情况:在做了多个Angular项目后转向React,没有一个简单的方法通过DI提供服务似乎是一个缺失的部分(抛开服务的细节不谈)。

使用context和ES7装饰器,我们可以接近:

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经验。考虑一下逻辑的本质:

它是否(仅)绑定到UI?将其移动到组件中(已接受的答案)。 它(只)与国家管理有关吗?移动到一个坦克。 两者都有关系?移动到单独的文件,在组件中通过选择器和坦克消费。

有些人还使用hoc进行重用,但对我来说,以上几乎涵盖了所有用例。另外,考虑使用鸭子来扩展状态管理,以保持关注点的独立性和以状态ui为中心。

其他回答

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

每次用户需要输入新密码时,你都需要用到它。这可能出现在注册屏幕、“忘记密码”屏幕、管理员“为其他用户重置密码”屏幕等。

但在这些情况下,它总是会绑定到某个文本输入域。这就是它们应该耦合的地方。

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

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

可以使用export关键字从包含必要方法的文件中使用函数。

让我举个例子。假设我们有一个名为someservices .ts的文件:

export const foo = (formId: string) => {
    // ... the code is omitted for the brevity
}


export const bar = (): Entity[] => [
    // ... the code is omitted for the brevity
]

export default {
    foo,
    bar,
}

然后我们可以像这样在组件中使用这个服务:

import {
    foo,
    bar,
} from './someService'

const InnerOrderModal: FC = observer(() => {
    const handleFormClick = (value: unknown, item: any) => {
    foo(item.key)
    bar()
    
    return <></>
}

我需要一些可以在多个组件间共享的格式化逻辑,而作为Angular开发人员,我自然也倾向于使用服务。

我通过将其放在一个单独的文件中来共享逻辑

function format(input) {
    //convert input to output
    return output;
}

module.exports = {
    format: format
};

然后把它作为一个模块导入

import formatter from '../services/formatter.service';

//then in component

    render() {

        return formatter.format(this.props.data);
    }

我和你处境相同。在你提到的情况下,我将输入验证UI组件实现为一个React组件。

我同意验证逻辑本身的实现应该(必须)不耦合。因此,我会把它放在一个单独的JS模块中。

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

这允许独立地进行依赖注入和单元测试。

如果你还在寻找像Angular这样的服务,你可以尝试react-rxbuilder库

您可以使用@Injectable来注册服务,然后您可以使用useService或CountService。在组件中使用服务

import { RxService, Injectable, useService } from "react-rxbuilder";

@Injectable()
export class CountService {
  static ins: CountService;

  count = 0;
  inc() {
    this.count++;
  }
}

export default function App() {
  const [s] = useService(CountService);
  return (
    <div className="App">
      <h1>{s.count}</h1>
      <button onClick={s.inc}>inc</button>
    </div>
  );
}

// Finally use `RxService` in your root component
render(<RxService>{() => <App />}</RxService>, document.getElementById("root"));

预防措施

取决于rxjs和typescript 不能在服务中使用箭头函数