我来自angular世界,在那里我可以提取逻辑到服务/工厂,并在我的控制器中使用它们。
我试图了解如何在React应用程序中实现相同的功能。
假设我有一个验证用户密码输入的组件(它的强度)。它的逻辑相当复杂,因此我不想把它写在组件中。
我应该把这个逻辑写在哪里?如果我在商店里使用助焊剂?还是有更好的选择?
我来自angular世界,在那里我可以提取逻辑到服务/工厂,并在我的控制器中使用它们。
我试图了解如何在React应用程序中实现相同的功能。
假设我有一个验证用户密码输入的组件(它的强度)。它的逻辑相当复杂,因此我不想把它写在组件中。
我应该把这个逻辑写在哪里?如果我在商店里使用助焊剂?还是有更好的选择?
当前回答
我和你处境相同。在你提到的情况下,我将输入验证UI组件实现为一个React组件。
我同意验证逻辑本身的实现应该(必须)不耦合。因此,我会把它放在一个单独的JS模块中。
也就是说,对于不应该耦合的逻辑,在单独的文件中使用JS模块/类,并使用require/import将组件与“服务”解耦。
这允许独立地进行依赖注入和单元测试。
其他回答
我也来自Angular.js领域,React.js中的服务和工厂更简单。
你可以像我一样使用普通的函数或类,回调样式和事件Mobx:)
// Here we have Service class > dont forget that in JS class is Function class HttpService { constructor() { this.data = "Hello data from HttpService"; this.getData = this.getData.bind(this); } getData() { return this.data; } } // Making Instance of class > it's object now const http = new HttpService(); // Here is React Class extended By React class ReactApp extends React.Component { state = { data: "" }; componentDidMount() { const data = http.getData(); this.setState({ data: data }); } render() { return <div>{this.state.data}</div>; } } ReactDOM.render(<ReactApp />, document.getElementById("root")); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> </body> </html>
这里有一个简单的例子:
如果你还在寻找像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 不能在服务中使用箭头函数
Service并不局限于Angular,甚至在Angular2+中也是如此,
Service只是helper函数的集合…
有很多方法可以创建它们并在应用程序中重用它们……
1)它们可以都是从js文件导出的分离函数,如下所示:
export const firstFunction = () => {
return "firstFunction";
}
export const secondFunction = () => {
return "secondFunction";
}
//etc
2)我们也可以使用工厂方法,比如函数的集合…在ES6中,它可以是一个类而不是函数构造函数:
class myService {
constructor() {
this._data = null;
}
setMyService(data) {
this._data = data;
}
getMyService() {
return this._data;
}
}
在这种情况下,你需要用new key创建一个实例…
const myServiceInstance = new myService();
同样,在这种情况下,每个实例都有自己的生命周期,所以如果你想跨界共享它要小心,在这种情况下,你应该只导出你想要的实例……
3)如果你的函数和utils不会被共享,你甚至可以把它们放在React组件中,在这种情况下,就像函数在React组件中一样…
class Greeting extends React.Component {
getName() {
return "Alireza Dezfoolian";
}
render() {
return <h1>Hello, {this.getName()}</h1>;
}
}
4)另一种你可以处理事情的方法,可以使用Redux,它是你的临时存储,所以如果你在你的React应用程序中有它,它可以帮助你使用许多getter setter函数…它就像一个大的存储,可以跟踪你的状态,并可以在你的组件之间共享它,所以可以摆脱我们在服务中使用的getter setter的许多痛苦……
做一个DRY代码总是好的,不要重复需要使用的东西来让代码可重用和可读,但不要试图在React应用中遵循Angular的方法,就像第4项提到的,使用Redux可以减少你对服务的需求,你可以限制在一些可重用的帮助函数上使用它们,比如第1项……
同样的情况:在做了多个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为中心。
我和你处境相同。在你提到的情况下,我将输入验证UI组件实现为一个React组件。
我同意验证逻辑本身的实现应该(必须)不耦合。因此,我会把它放在一个单独的JS模块中。
也就是说,对于不应该耦合的逻辑,在单独的文件中使用JS模块/类,并使用require/import将组件与“服务”解耦。
这允许独立地进行依赖注入和单元测试。