5个React架构最佳实践

160 阅读5分钟

毫无疑问,React已经彻底改变了我们构建用户界面的方式。它很容易学习,并极大地促进了创建可重复使用的组件,为你的网站提供了一致的外观和感觉。

然而,由于React只负责应用程序的视图层,它并不强制执行任何特定的架构(如MVC或MVVM)。这可能会使你在React项目增长时难以保持你的代码库的组织性。

9elements,我们的旗舰产品之一是PhotoEditorSDK--一个完全可定制的照片编辑器,可以轻松集成到你的HTML5、iOS或Android应用中。PhotoEditorSDK是一个针对开发者的大规模React应用。它需要高性能、小规模的构建,并且需要在风格设计,特别是主题设计方面非常灵活。

在PhotoEditorSDK的多次迭代过程中,我和我的团队总结了一些组织大型React应用的最佳实践,其中一些我们想在本文中与你分享。

1.目录布局

最初,我们的组件的样式和代码是分开的。所有的样式都存在于一个共享的CSS文件中(我们使用SCSS进行预处理)。实际的组件(在这个例子中是FilterSlider )与样式是分离的。

├── components
│   └── FilterSlider
│       ├──  __tests__
│       │   └── FilterSlider-test.js
│       └── FilterSlider.jsx
└── styles
    └── photo-editor-sdk.scss

经过多次重构,我们发现这种方法并不能很好地扩展。在未来,我们的组件需要在多个内部项目之间共享,比如SDK和我们目前正在开发的实验性文本工具。所以我们转而采用以组件为中心的文件布局。

components
    └── FilterSlider
        ├── __tests__
        │   └── FilterSlider-test.js
        ├── FilterSlider.jsx
        └── FilterSlider.scss

我们的想法是,所有属于一个组件的代码(如JavaScript、CSS、资产、测试)都位于一个文件夹中。这使得将代码提取到npm模块中变得非常容易,或者在你匆忙的情况下,可以简单地与另一个项目共享这个文件夹。

导入组件

这种目录结构的缺点之一是,导入组件需要你导入完全合格的路径,像这样。

import FilterSlider from 'components/FilterSlider/FilterSlider'

但我们真正想写的是这个。

import FilterSlider from 'components/FilterSlider'

为了解决这个问题,你可以创建一个index.js ,并立即导出默认。

export { default } from './FilterSlider';

另一个解决方案的范围更广一些,但它使用了Node.js标准的解析机制,使得它坚如磐石,经得起未来考验。我们所做的就是在文件结构中添加一个package.json 文件。

components
    └── FilterSlider
        ├── __tests__
        │   └── FilterSlider-test.js
        ├── FilterSlider.jsx
        ├── FilterSlider.scss
        └── package.json

而在package.json ,我们使用main属性来设置我们的组件入口点,像这样。

{
  "main": "FilterSlider.jsx"
}

有了这个补充,我们可以像这样导入一个组件。

import FilterSlider from 'components/FilterSlider'

2.JavaScript中的CSS

样式设计,尤其是主题设计,一直是个问题。如上所述,在应用程序的第一次迭代中,我们有一个大的CSS(SCSS)文件,其中包含了我们所有的类。为了避免名称冲突,我们使用了一个全局前缀,并遵循BEM惯例来制作CSS规则名称。当我们的应用程序增长时,这种方法不能很好地扩展,所以我们寻找一个替代品。首先,我们评估了CSS模块,但当时它们有一些性能问题。另外,通过webpack的Extract Text插件来提取CSS的效果也不是很好(尽管在写这篇文章的时候应该是可以的)。此外,这种方法对webpack产生了严重的依赖性,使得测试相当困难。

接下来,我们评估了最近出现的一些其他CSS-in-JS解决方案。

选择这些库中的一个在很大程度上取决于你的使用情况。

  • 你是否需要这个库来吐出一个编译好的CSS文件用于生产?EmotionJS和Linaria可以做到这一点!Linaria甚至不需要运行时间。它通过CSS变量将道具映射到CSS,这就排除了对IE11的支持--但无论如何谁需要IE11?
  • 它需要在服务器上运行吗?这对所有库的最新版本来说都不是问题!

对于目录结构,我们喜欢把所有的样式放在一个styles.js

export const Section = styled.section`
  padding: 4em;
  background: papayawhip;
`;

这样,纯粹的前端人员也能够编辑一些样式,而不需要处理React,但他们必须学习最少的JavaScript,以及如何将props映射到CSS属性。

components
    └── FilterSlider
        ├── __tests__
        │   └── FilterSlider-test.js
        ├── styles.js
        ├── FilterSlider.jsx
        └── index.js

把你的主组件文件从HTML中解压出来是一个很好的做法。

努力实现React组件的单一责任

当你开发高度抽象的UI组件时,有时很难分开关注点。在某些时候,你的组件会需要来自你的模型的某种领域逻辑,然后事情就变得混乱了。在下面的章节中,我们想向你展示某些方法,以便将你的组件干化。下面的技术在功能上是重叠的,为你的架构选择合适的技术更多的是一种风格上的偏好,而不是基于硬性的事实。但让我先介绍一下用例。

  • 我们不得不引入一种机制来处理那些对登录用户有上下文感知的组件。
  • 我们不得不用多个可折叠的<tbody> 元素来渲染一个表格。
  • 我们必须根据不同的状态来显示不同的组件。

在下面的章节中,我将展示针对上述问题的不同解决方案。

继续阅读5 React Architecture Best Practices for 2021onSitePoint.