Hexagonal六角形架构ReactJS的实现方式 - Janos Pasztor

解道jdon 2021-05-03 16:57:25
架构 六角 角形 六角形 hexagonal


ReactJS是前端开发的主力,但它在SOLID方面表现不佳我们可以通过采用经典方法来改变它吗?

在将ReactJS视为UI的现代JavaScript解决方案时,很多人似乎在组织代码时遇到问题。让我们深入了解一下,看看我们是否可以做得更好。

性子急的人可立即获取代码

什么是React?

自从我20年前开始进行Web开发以来,在JavaScript中编写前端代码一直是一次痛苦的经历。主要是由于浏览器不兼容,还因为没有可行的组件框架。果然,ExtJS和新的Sencha已经上市,但使用它比使用起来更痛苦。

然后React出现了,试图解决这些问题,React使用了JS的下一代版本,您可以将其 转换为适用于当前可用的浏览器。在React中,您可以创建可重用的组件,例如:

class MyBlogComponent {
    render() { 
        return <div className="blogentry">
          <div className="blogentry__title">{this.props.title}</div>
          ...
        </div>;
    }
}

然后你可以在其他组件中使用这些组件:

class FeaturedBlogPost {
    render() {
        return <MyBlogComponent title="Featured article" />;
    }
}

这些组件中的每一个都有两个部分:属性和状态。属性props是从外部传递的参数数据。在上面的例子中,“title”是一个属性。另一方面,状态是组件内部状态。内部状态的一个很好的例子是当你需要从组件中的服务器加载数据然后显示它时。

这些组件最终创建了所谓的虚拟DOM。这是一棵树,就像真正的DOM一样,但它更快,更快。事实上,如此快速,它可以为每个状态变化重新计算整个DOM。

然后,React会接受虚拟DOM并比较不同版本,以便找出真正DOM需要更新的部分。

FLUX/REDUX架构

正如您可能想象的那样,最初的实现并不是完全无瑕疵的。每个组件都需要维护自己的内部状态,当两个不同的组件使用相同的数据时,通常会出现不一致的情况,因为数据将在不同的时间从服务器加载。

试图解决这个问题,FLUX或REDUX架构诞生了。两者略有不同,但为了本文的目的,我们将它们视为一个。

核心思想是应用程序具有一个中央状态,可以将所有内容存储在应用程序中。当组件触发操作时,该操作将改变状态(通过操作创建器功能),这反过来将使用该全局状态更改组件的呈现内容。

当然,这提供了一种集中式架构,可以从单个组件中分离出状态处理,使其自然呈现。

但是,正如您可能已经猜到的那样,这种架构也有其平衡的问题。首先,它有一个集中 状态,基本上是一个存储应用程序中所有数据的巨型上帝对象。我的第二个问题集中在解决方案的非SOLID问题上。为了更改应用程序的一部分,您必须在应用程序中触摸(并测试)各种代码部分,并且数据结构的更改可能会产生广泛的后果。

六角形Hexagonal架构

对我来说非常好的一种架构是六边形/六角形,或者我喜欢称之为饼干cutter架构。这种架构利用的服务来进行操作,而实体entites作为结构化格式数据传输。

很长一段时间,我没有办法在Javascript中重新创建这个架构,因为它没有依赖注入或静态类型。然而,最近,我一直在使用Typescript和Blueprint作为React的组件框架,我设法找到了构建类似系统的方法。

首先,我们将从业务逻辑开始。例如,我们将构建一个AuthenticationService。与我之前描述后端架构的文章相反,存储状态的主要位置将是服务层。因此,身份验证服务有几个本地字段:

class AuthenticationService {
    private accessToken: IAccessToken|null = null;
    private account: IAccount|null = null;
}

这些实体可以定义为这样的简单接口:

interface IAccessToken {
    readonly id: string;
    readonly accountId: string;
    readonly expires: LocalDateTime;
}

当转换为JavaScript时,这些将由常规对象表示。由于我们正在构建服务,因此我们还需要一些依赖项,这些依赖项可以按预期通过构造函数注入:

class AuthenticationService {
    //...
    public constructor(
        readonly authenticationBackend: IAuthenticationBackendApi
    ) {
    }
}

最后,让我们添加身份验证方法:

class AuthenticationService {
    //...
    public authenticate = (username: string, password: string): Promise<boolean> => {
       
    };
}

正如您所看到的,我们正在使用promises,因为身份验证过程需要时间。promises完成后,身份验证过程已完成或失败。然后我们可以实现这样的登录表单:

class AuthenticationDialog
    extends React.Component<IAuthenticationDialogProps, IAuthenticationDialogState>
{
    render = () : JSX.Element => {
        return <form>
          <input ... />
          <input ... />
          <button onClick={this.onLogin} />
        </form>
    };
    private onLogin = () => {
        this.setState({
            loading: true
        });
        const self = this;
        this.props.authenticationService
            .authenticate(this.state.username,this.state.password)
            .catch(() => {
                self.setState({
                    loading: false
                });
                //Authentication process failure
            })
            .then((result: boolean) => {
                self.setState({
                    loading: false
                });
                if (result) {
                    //Successful login
                } else {
                    //Failed login
                }
            })
    };
}

处理事件

到目前为止,我们只对事件作出反应 那么你如何根据正在发生的事件更新React组件?让我们坚持使用身份验证示例。我们来看看我们的身份验证服务:

class AuthenticationService {
    //...
    registerAuthenticationChangeListener(listener: IAuthenticationChangeListener):void {
    }
    deregisterAuthenticationChangeListener(listener: IAuthenticationChangeListener):void {
    }
}

所以我们添加了这两个新函数,允许组件将自己注册为事件监听器。在组件中,您可以执行以下操作:

class RequireAuthenticated
    extends React.Component
    implements IAuthenticationChangeListener
{
    public state : IAuthenticationContextState = {
        isAuthenticated: false
    };
    public componentDidMount = (): void => {
        this.props.authenticationService.registerAuthenticationChangeListener(this);
        this.onAuthenticationChange();
    };
    public onAuthenticationChange = ():void => {
        this.setState({
            isAuthenticated: this.props.authenticationService.isAuthenticated()
        });
    };
    public render = () => {
        return this.state.isAuthenticated?this.props.children:[];
    }
}

如您所见,此组件仅在用户通过身份验证时显示其内容。当组件出现时,它会将自身注册到身份验证服务,以便在状态发生变化时得到通知。这将允许DOM树在状态发生变化时发生变化。

构造组件树

您可能会注意到身份验证对话框将身份验证服务作为prop。因此,当您想要创建此身份验证对话框时,您必须这样做:

const authService = new AuthenticationService();
const authDialog = <AuthenticationDialog authenticationService={authService} />

显然,这使得创建组件树的过程有点混乱。要解决这个问题,我们将使用工厂:

class AuthenticationDialogFactory {
    public constructor(
        readonly authenticationServiceFactory: AuthenticationServiceFactory
    ) {
    }
    public create = () : JSX.Element => {
        return <AuthenticationDialog
            authenticationService={this.authenticationServiceFactory.create()}
        />
    }
}

然后将在我们的index.jsx文件中使用此工厂来构建根应用程序。

获取代码

现在您已经很好地了解了正在发生的事情,您可以 从GitHub中获取代码

此外,您可以通过添加React.DI来扩展此解决方案。

结论

在我的试验期间,我发现编写和调试这样的代码非常容易。这是更多的字节,但它在调试东西时可以省去很多麻烦。但是,它不是唯一可行的解​​决方案。

版权声明
本文为[解道jdon]所创,转载请带上原文链接,感谢
https://www.jdon.com/51385

  1. 浅谈 React 中的 XSS 攻击
  2. XSS attack in react
  3. 自学前端教程整理,附不容错过的前端100篇文章合集
  4. Self taught front-end tutorial collation, with a collection of 100 front-end articles that can not be missed
  5. 使用OpenTracing跟踪Go中的HTTP请求延迟
  6. Using opentracing to track HTTP request latency in go
  7. Encapsulating databinding allows you to write less than 10000 lines of code
  8. 03-HTML5标签-HTML5极速入门
  9. 03-html5 tag-html5 quick start
  10. LayUI - 极易上手拿来即用的前端 UI 框架
  11. Layui - easy to use front end UI framework
  12. Interpretation of lodash source code (1)
  13. Why is the first parameter of node family callback error?
  14. 报告:JavaScript 开发者达1380 万,C#超越 PHP,Rust 增长最快
  15. Report: Javascript developers reach 13.8 million, C surpasses PHP, and rust grows fastest
  16. 小白前端入门笔记(10),怎么设置网站内部的超链接?
  17. How to set up hyperlinks inside the website?
  18. Using node and socket to realize online chat room
  19. The core competitiveness of Vue: data bidirectional binding
  20. React configuration agent
  21. CSS layout
  22. Application scenario explanation of Vue dynamic component
  23. Redux learning notes 04 -- using multiple reducers to manage data
  24. After three months of typescript writing, what have I learned?
  25. Node family - what is a callback?
  26. React -- a simple implementation of render & create element
  27. JS learning simple usage of jquery
  28. Seamless love
  29. 小白前端入门笔记(12),设置哑链接
  30. Small white front-end entry notes (12), set dumb links
  31. Vue2. X opens composition API and TSX
  32. Interview record and thinking of social recruitment for one and a half years (Alibaba, Tencent, baidu offer)
  33. Flex learning notes
  34. The most essential closure article in the eastern hemisphere
  35. 2021-05-03 hot news
  36. Sword finger offer -- reverse order pair in array (JS Implementation)
  37. Working process of scaffold
  38. Use decorator mode to strengthen your fetch
  39. [JS] scope (Introduction)
  40. Employment information statistics network (interface document)
  41. Analysis of MVC
  42. [middle stage] please stay and join me in the backstage
  43. Understanding front end garbage collection
  44. [continuous update] front end special style implementation
  45. Flutter product analysis and package reduction scheme
  46. XPath positioning
  47. 前端开发css中的flex布局的使用
  48. The use of flex layout in front end development CSS
  49. JQuery核心函数和静态方法
  50. JQuery core functions and static methods
  51. Node family - understanding of blocking and non blocking
  52. 热点微前端Microfrontend的讨论:谷歌AdWords是真实的微前端
  53. Vue source code analysis (2) initproxy initialization proxy
  54. What's TM called react diff
  55. Summary of common front end data structure
  56. Useeffect in hooks
  57. [encapsulation 02 design pattern] Command pattern, share meta pattern, combination pattern, proxy pattern, strategy pattern
  58. Front end notes: virtual Dom and diff of vue2. X
  59. The best code scanning plug-in of flutter
  60. The simplest plug-in for rights management of flutter