首页 > web前端 > js教程 > 模块化 React 架构

模块化 React 架构

Linda Hamilton
发布: 2024-11-09 19:29:02
原创
373 人浏览过

Modular React architecture

浅谈模块化架构

什么是模块化架构?让我们通过一个例子来了解它不是什么,并且
我们将努力改变它。到最后你可能会相信它
优点或这是对时间的巨大浪费。

这是我在工作中经历的一个成长心态的真实场景。姓名和详细信息
虽然是匿名的,但一个常见概念的现实世界示例应该很有趣
如果没有别的的话,通过。

要求以及如何找到它们

我们的网站有一个位于网站标题中的按钮。它显示有多少
用户已经离开了 V-Bucks,但也融入了一些业务逻辑:

  • 如果这是他们第一次访问该网站,请打开一个弹出窗口来欢迎他们 并展示他们可以用 V-Bucks 做些什么
  • 如果他们有
  • 如果他们是基本用户,则显示一种样式的按钮;如果是 SuperDuper 用户,则显示 另一个更漂亮的按钮

等等。我们的产品经理和项目经理这样的例子还有很多
设计经理和 V-Bucks 集团董事梦想着我们需要
手柄。

实习生 Jimbo 的任务是实现这个,因为这只是一个
按钮!

他筛选了 Figma 设计的 15 种相互冲突的迭代。他发现
有多少个 PM,就在多少个单独的 Word 文档中包含这些要求。他组织并
与七个团队一起进行七次知识转移会议,以揭开
古老的专有知识知道哪些服务将提供他所需的数据
用于用户类型和 V-Bucks 数量。内容团队向他保证
所有字符串的最终版本将在年底获得法律和营销部门的批准
一周,这样,他就准备好构建这个按钮了。

黑客方法

这是他的 V-Bucks 按钮、弹出窗口和相关内容的第一次迭代
业务逻辑。

Jimbo 对他提出的简单目录结构感到满意:

/v-bucks-button
├── button.tsx
├── index.ts
└── /v-bucks-popover
│ ├── popover.tsx
登录后复制
登录后复制
登录后复制

所以他开始构建这个按钮,而且一开始很天真。

export const VBucksButton: React.FC<VBBProps> = ({ ... }) => {
  // Set up state
  const authConfig    = { ... }
  const { user }      = useAuth({ ...authConfig })
  const { vBucks }    = useGetVBucks({ user })
  const { telemetry } = useTelemetry()
  const { t }         = useTranslation('vBucksButton.content')
  const styles        = useButtonStyles()

  // Derive some state via business logic
  const handleClick = () => { ... }
  const buttonText  = vBucks === ERROR ? '--' : vBucks.toString();
  // About 25 more lines of various button state, error handling,
  // conditional rendering, with comments throughout explaining
  // why we're showing or hiding something or other

  const popoverProps = {
    // About 200 lines of typical popover handling,
    // telemetry, business logic, content to display, etc
  }

  const tooltipProps = {
    // Another 100 lines of the same for tooltip
  }

  return (
    <VBucksPopover
      {...popoverProps}
      trigger={
        <Tooltip {...tooltipProps}>
          <button
            ariaLabel={t('ariaLabel')}
            className={`
              about seven-hundred classnames for responsive design,
              accessibility, conditional premium styles, et cetera`}
            onClick={handleClick}>
            {buttonText}
          </button>
        </Tooltip>
      }
    />
  )
}
登录后复制
登录后复制

他已经实现了第一次尝试。 VBucksPopover 也有类似的复杂
业务逻辑、错误处理、状态管理、样式和注释
以运输名义的技术债务。

这个按钮只有不到 400 行,非常简单。即使弹出窗口是
另外500行意大利面条。真的是“清理”还是分裂
以任何方式使我们或我们的用户受益?这取决于。如果这就是我们所需要的
这个按钮,谁在乎呢。让我们继续前进吧!

但是两个月过去了,另一个产品团队的PM和设计师爱上了
您的按钮并希望将其放在应用程序的标题中。他们有一个简单列表,没有
来自他们的压力,他们希望你适应一些改变,如果
您可以在当天结束前给出 LT 的预计到达时间,那就太好了,谢谢:

  • 更新按钮的样式并根据其显示的应用程序显示文本
  • 每个应用程序显示一组完全不同的弹出窗口
  • 当用户用完 V-Bucks 时,打开一个新的全公司范围内的标准追加销售模式, 但仅限于某些地区,并且仅限 16 岁的用户,并且仅限于 实验A组

Jimbo 能否将所有这些新功能塞进同一个组件中?

是的。拆分或重构会给用户带来好处还是给你的经理留下深刻印象?

不。但是在这种复杂程度上,重构有一些强有力的论据:

  • 开发理智
  • 当 Jimbo 因不重构而被 PIP 时取代他的开发人员的理智
  • 更多次数,让你下次从一开始就做得更好
  • 稍后写博客的内容

模块化架构方法

清洁守则倡导者和其他了解足够知识的肛门类型的道德
定期在 Stack Overflow 上回答,甚至你的祖父母也会看一些东西
像这样:

  • KISS、DRY 和其他缩写毯子
  • 关注点分离
  • 原子性!脱钩!拟声词!

这些都很棒,有助于为 Jimbo 的下一次尝试提供信息。
之后他就没有被画中画了 所有,而且实际上还得到了提前交付和分享的促销
这么多的会议和文件。

但他现在更聪明了,学会了一种很酷的方法来实践这些格言。看起来
像这样的东西:

/v-bucks-button
├── button.tsx
├── index.ts
└── /v-bucks-popover
│ ├── popover.tsx
登录后复制
登录后复制
登录后复制

看起来像大量按钮和弹出框的样板。为什么会这样
更好吗?

这取决于。以下是 Jimbo 的简要概述及其基本原理:

  • 将每个组件拆分为容器和渲染器
  • 将状态和业务逻辑移入钩子
  • 容器使用钩子并将任何道具传递给渲染器
  • 渲染器只关心渲染它所提供的内容
  • 通用功能、业务逻辑或常量可以存在于 utils 中
  • 不同类型的单独文件;它们往往被导入到多个文件中并且 成为你无论如何都需要提取的循环依赖
  • 提取的 TailwindCSS - 下面有更多内容

无限可扩展!这些构建块不会被
分解 任意规则,例如代码行或“复杂性”。它们被分解为
目的:每个概念边界都有一个目的。

PM 要你制作 10 个新的爆米花?没问题——Jimbo 的架构可以
处理一下。

领导层希望在某些应用程序中获得更好的销售指标,但其他团队则不然
有资金建立遥测技术来支持这一点。伟大的!我们有
我们可以水平扩展以满足各种变化的遥测实用程序
要求。

彻底的重新设计意味着每个弹出窗口都需要显示不同的内容,
根据不同的条件。现在,通常要简单得多,因为所有
我们渲染的东西,以及我们用来渲染它的所有逻辑,都存在于明确定义的
中 块。它们不再混杂在一大堆冲突和逻辑中
链长 20 行。

这是此容器/渲染器模式的示例:

/v-bucks-button
├── button.tsx
├── index.ts
└── /v-bucks-popover
│ ├── popover.tsx
登录后复制
登录后复制
登录后复制
export const VBucksButton: React.FC<VBBProps> = ({ ... }) => {
  // Set up state
  const authConfig    = { ... }
  const { user }      = useAuth({ ...authConfig })
  const { vBucks }    = useGetVBucks({ user })
  const { telemetry } = useTelemetry()
  const { t }         = useTranslation('vBucksButton.content')
  const styles        = useButtonStyles()

  // Derive some state via business logic
  const handleClick = () => { ... }
  const buttonText  = vBucks === ERROR ? '--' : vBucks.toString();
  // About 25 more lines of various button state, error handling,
  // conditional rendering, with comments throughout explaining
  // why we're showing or hiding something or other

  const popoverProps = {
    // About 200 lines of typical popover handling,
    // telemetry, business logic, content to display, etc
  }

  const tooltipProps = {
    // Another 100 lines of the same for tooltip
  }

  return (
    <VBucksPopover
      {...popoverProps}
      trigger={
        <Tooltip {...tooltipProps}>
          <button
            ariaLabel={t('ariaLabel')}
            className={`
              about seven-hundred classnames for responsive design,
              accessibility, conditional premium styles, et cetera`}
            onClick={handleClick}>
            {buttonText}
          </button>
        </Tooltip>
      }
    />
  )
}
登录后复制
登录后复制
/vBucksButton
├── /hooks
│ ├── index.ts
│ └── useButtonState.hook.ts
├── /vBucksPopover
│ ├── /app1Popover
│ │ ├── /hooks
│ │ │ ├── index.ts
│ │ │ └── usePopoverState.hook.ts
│ │ ├── ...
│ ├── /app2Popover
│ ├── index.ts
│ ├── popover.renderer.tsx
│ ├── popover.styles.ts
│ ├── popover.tsx
│ └── popover.types.ts
├── /utils
│ ├── experimentation.util.ts
│ ├── store.util.ts
│ ├── telemetry.util.ts
│ └── vBucks.businessLogic.util.ts
├── button.renderer.tsx
├── button.styles.ts
├── button.tsx
├── button.types.ts
└── index.ts
登录后复制

旁白:TailwindCSS 文档明确建议不要使用 @apply 来提取这样的公共类。这导致包大小几乎为零差异,除了“你必须想出类名”之外没有其他差异。生产级 CSS 几乎总是有几十行那么长,乘以给定组件中需要样式化的元素数量。这种权衡在 90% 的情况下似乎都是值得的。

其余现有的和新的业务逻辑位于钩子和实用程序中!

这种新架构满足了狂热者的需求,并使事情更容易扩展或
删除或移动。

编写单元测试变得不那么痛苦,因为你已经有了明确的定义
边界。您的渲染器不再需要模拟十种不同的服务来
验证它是否在给定一些输入的情况下显示了一组闪光。你的钩子可以
单独测试它们是否符合您预期的业务逻辑。

你的整个状态层刚刚改变了吗?如果您的
中的代码那就太可惜了 钩子与使用它的代码紧密耦合,但现在它更简单
更改,您的渲染器仍然只是等待一些输入。

最后的想法

这种模块化架构添加了大量样板,最终可以提供
零利益。

如果您正在从事一个充满激情的项目或
,我实际上无法推荐它 优先考虑运输和提供价值。如果你有
的东西 似乎它的范围可能会随着时间的推移而扩大,或者您可能想要
在 POC 后进行彻底检修,有时可以减少技术债务。

您可以使用 Plop 等工具来生成此样板。

那么我从 Jimbo 的工作和模块化架构中真正学到了什么?

我们在学校和世界各地的 Well Ackshuallys 中学习的干净代码和缩写词
是一系列的一端。将功能性意大利面条代码组合在一起是另一回事
结束,并且通常效果很好,因为最终所有代码都是技术债。

最佳解决方案存在于某种量子态或这些末端的组合中,并且
我们选择的路径可能取决于:

  • 我们有多关心我们正在构建的东西
  • 管理层要求更新和预计到达时间的频率
  • 读到这样的东西,一种方法恰好出现在你的 当你构建下一个东西时的意识
  • 沮丧、痛苦
  • 意大利面变成了性能瓶颈,你不得不重写它
  • 样板文件变得如此枯燥,以至于你不得不偷工减料

以上是模块化 React 架构的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板