React - 没有 Redux 的可扩展架构(MVC + DDD 方法)

Posted

技术标签:

【中文标题】React - 没有 Redux 的可扩展架构(MVC + DDD 方法)【英文标题】:React - Scalable architecture without Redux (MVC + DDD approach) 【发布时间】:2021-12-28 08:39:29 【问题描述】:

简介

React 真的很灵活,似乎我们在编写接口时不必遵循特定的架构,与其他库不同,它就像编写普通视图一样。对于小型 Web 应用程序,这很酷,但是......一旦您的应用程序开始增长,您的编码速度就会逐渐降低,这与您从一开始就定义了架构的原则相反。

我的架构

就我而言,我没有使用 Redux 进行状态管理...相反,我使用的是 React Context + React Hooks。

这是我当前的项目结构(使用 firebase 构建的无服务器应用程序):

/app
   /components
      /Activity
      /Authentication
      /Profile
      /Buttons
      /Text
      /Inputs
      /Giphy
      /Messaging
      /HOCs
      ...

   /screens
      /Activity
      /Authentication
      /Profile
      /Messaging
      ...
   
   /contexts
      /Users
      /Content
      /Auth
      ...

   /hooks
      /auth
      /profile
      /users
      /content
      /badges
      /i18n
      ...

   /navigation
      /Stacks
      /Tabs
      ...

   /services
      /third-party
      /firebase 
         /api
      ...

   /lib
   /theme
   /styles
   /utils


/functions (backend)

如您所见,我正在使用某种领域驱动设计来构建我的项目文件。

另外,我使用钩子将关注点与屏幕和组件分开,并在包含相应 reducer 的上下文中管理复杂状态(或需要在路由之间同步的状态)。

在我看来,这就像某种 MVC。视图由我所有的 React 功能组件组成,控制器由我所有的业务和 UI 钩子组成,我的模型的数据包含在上下文中(或者,至少是动态数据,因为效率原因)。

如您所见,我有一个“服务”文件夹,它只是我的业务挂钩用来连接到我的服务器(云功能)的接口。

问题

    这个架构有名字吗(flux/redux??)?我的意思是,随着时间的推移,作为一名 React 程序员,一个又一个错误,我最终以一种“自然”的方式组织我的项目。

    用钩子分割我的所有组件逻辑是一种反模式吗?我的意思是,所有我的项目的功能组件只包含事件处理程序或 JSX 来呈现 UI。我已经将每一个代码块都移动到了钩子中,其中一些包含我的业务逻辑,另一些只是与图形界面相关的复杂逻辑(动画,...)

    为了完善我当前的架构,您给了我哪些建议?

    使用带有 React 上下文的选择器?我已经实现了一些自定义钩子,它们只是从上下文中读取和计算派生数据......因为我不能使用“useSelector”,我不知道这是否是典型的,因为它们只是消耗必要的上下文(useContext)和然后执行一些计算。

    Redux 真的有必要吗?对于一个中型项目,我使用 React Context 处理得很好,并且在 hooks 的帮助下,我的代码非常干净。你认为随着时间的推移,随着项目的不断发展,是否有必要迁移到 Redux?

    react hooks 是应用程序的控制器吗?

【问题讨论】:

这似乎更像是一个包含多个未解决问题的一般架构讨论。你确定这是正确的地方吗?很多将归结为个人喜好。我已经看到了类似于“flux”的全局状态管理实现,其反应上下文与 redux 有点相似。在每种情况下,我都更喜欢 redux。它是众所周知的、已建立的,并将扩大规模。缺点(冗长,你可能永远不需要时间旅行,撤消等)并没有超过恕我直言的优点。我相信你会在另一个方向得到很多回应:) 【参考方案1】:

嗯,不完全确定这是提出此类问题的正确位置,但让我们尝试从我的角度来回答这些问题。

答案

    我认为这个特定的架构没有名称(例如,这个架构的名称为 https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)。在任何情况下,名称都不会是“Flux”或“Redux”,因为这些名称更多地与数据的处理方式相关,而不是项目中文件夹的结构方式。我不认为有一些关于文件夹层次结构的严格规则可以完全符合 Flux 或 Redux 模式。当然有最佳做法和惯例,但它们不是强制性的。 为了回答这个问题,让我分享这个链接https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 关于 Dan Abramov 发表的一篇文章。我分享这篇文章是因为上次更新(文章日期为 2015 年,但在 2019 年进行了重要更新)。如您所见,您似乎做得很好,因为您将核心逻辑放在了钩子中。只是关于这一点的说明:您说的是“功能组件”,但我认为您指的是“表示组件”,这是一个重要的区别,因为“功能组件”意味着您的组件基于函数(而不是类) ,“表示组件”反而意味着该组件不包含业务逻辑。 “表示组件”既可以是基于类的也可以是函数式的,并且函数式组件可以包含业务逻辑(基于类的组件正在被函数式组件取代,但这是另一回事)。 一些建议:大小写和大小写保持一致(你正在混合大写和小写,破折号和驼峰式,通常我喜欢用破折号命名每个文件或文件夹,但这取决于你);确定HOCs 文件夹是否应该在此处;也许你可以将所有的工具(libthemestylesutils 本身)放在一个名为 utils 的目录中,其中每个工具都被命名为属性; 关于上下文,这是一个有争议的话题,只是想分享一些从文档https://reactjs.org/docs/context.html#before-you-use-context 中获得的考虑并分享我对此的看法。根据文档副标题,上下文背后的想法是“上下文提供了一种通过组件树传递数据的方法,而无需在每个级别手动向下传递道具”。因此,基本上,它是为避免“财产钻探”而创建的,例如https://medium.com/swlh/avoid-prop-drilling-with-react-context-a00392ee3d8。这只是个人观点,但也许引入 Redux 来进行全局状态管理比使用 Context API 更好。 不要害怕使用 Redux。如果在使用 Redux 时,你有大量重复的代码行,你会感到害怕。在这种情况下,您应该考虑如何抽象您的动作和减速器(例如使用动作创建者)。如果您能够概括诸如“从后端获取项目列表”之类的内容,您将意识到您的代码不仅比重复的代码行更少,而且更具可读性和连贯性。例如,对于列表,您可能有类似 const getListOfNews = list("NEWS_LIST", "/api/news/"); 的操作,其中 list 是类似 const list = (resource, url) => (params = ) => dispatch => // your implementation... ; 的操作创建者,类似于 reducer。 不,他们只是“让您在不编写类的情况下使用状态和其他 React 功能”,如文档中的https://reactjs.org/docs/hooks-intro.html 所述。避免尝试将 MVC 之类的模式适应以不同想法创建的东西是很重要的,这是一个一般性建议。就像你来自 Angular 并尝试在 React 中以相同的方式工作。基本上,您应该使用 React 或其他库/框架,而不是试图将它们从原来的样子转变为您已经知道的样子。

【讨论】:

以上是关于React - 没有 Redux 的可扩展架构(MVC + DDD 方法)的主要内容,如果未能解决你的问题,请参考以下文章

React-Redux

React-redux: React.js 和 Redux 架构的结合

如何在 react-redux 中使用扩展运算符修改索引处的特定对象?

为啥初始状态没有保留在 react-redux 中

react-redux——使用redux——使用react-redux这个扩展

从 Redux 容器分派一个动作而不扩展 React.Component