Skip to content

xianengqi/turing-react-ant

Repository files navigation

引用ant design团队的issue编写高质量的业务组件

看了大佬的论述后,觉得非常棒,就摘抄下来,学习大佬的思路。

本文中以React为例, 但其中的观点及方法论,对 Vue, Angular 等同样适用.

React 于2013开源至今,已经过去了七年。这七年里,前端界从一开始对 HTML in JS(JSX) 等新概念的抗拒,到接受,并且在项目中大量使用。现在,React 已经改变了 View 层的开发方式。

可惜对于不少人而言,使用React 也只是改变了他们的开发方式而已。React所提供的,以组件的方式拆分 View 层代码,并通过组件组合的方式搭建页面,这一基本能力并没有被充分发挥。从我过去三年接触过的React项目来看,大多数的开发者(全栈 & 专业前端),只是把组件当作拆分代码的方式,很少会去思考组件该如何设计。结果就是,在项目里随处都能看到组件与 owner 的逻辑, 样式强耦合.

在使用了 React 的前提下,项目里却还是一大堆没有正确封装且相互之间高度耦合的组件,相当讽刺(毕竟 React 在 README.md 里面可是强调了 Component-Based),却在意料之中。因为, React 只是降低了组件实现的难度,并没有降低组件设计的难度。

为了提高项目的质量,我们需要提高项目中 React 组件的设计质量。如果项目只有一个开发者,事情相对容易,只需要不断地提高个人的组件设计能力,并保持相关意识即可。但对由多人协作开发的项目而言,还需要有相应的开发流程保证,才能全面的提高整个项目的质量,如 EsLint 之于代码风格。

但在介绍相应的方法论之前,得先讨论一个更加基本的问题。

为什么需要设计良好的组件


对于业务线的开发者而言,在组件设计上花费较多时间,似乎不是一件值得的事情。毕竟业务系统中的组件,往往只有一个使用场景,所以即使组件与其使用场景强耦合,也不是什么罪过。

对一次性项目而言,如活动页,这个论点是对的。但对于需要长期维护的项目而言,一个组件从开发完成,到最终被废弃,它的使用场景其实是不断变化的,因为项目在不断地迭代,重构。例如,C 组件在一开始是在 A 组件下,

image

一段时间后,A 组件被大幅度重构,可以理解为 A 被一个更好的实现 D 替代了,

image

如果 A 与 C 强耦合,那么这次重构将会非常辛苦,C 也需要面临本可以避免的重构。可见,设计良好的组件,能够降低重构的成本。

当然,上面提到的优点是建立在一个组件会被长期使用,随着项目不断迭代的前提下。但前端界面是一个非常不稳定的存在,一个组件被开发出来用不了多久可能就被废弃了,这还有认真设计的必要么?

即使是会被废弃的组件,仍然需要有良好的设计。同样是上面的例子, A 组件被替换为 D 组件后, root 中与 A 相关的代码必然需要调整。如果 root 与 A 强耦合, 那么 root 就需要较大的改动,而如果 A 是封装良好的组件,那么 root 中只需要移除 A 相关的 state 与 handler 即可。可见,设计良好的组件,能相对容易的移除,被其他组件替换或替换其他组件。

以上。

以下。

在一个隔离的环境中开发组件


与其在开发组件时,时刻堤防着不能与其他组件耦合,还不如直接在一个隔离的环境中开发组件,其实这也是通用组件的开发方式。

为了方便读者理解与实践,接下来会用Storaybook + DvaJS 展示该方法论。必须强调的是,工具和框架是可以自由选择的。

接入 Storybook

  1. npm install dva-cli-g 安装dva-cli, 然后运行 dva ne demo 生成项目目录。
  2. npm i -g @storybook/cli 安装storybook, 然后在 1 创建的项目中运行 getstorybook
  3. 更新 package.json 中的脚本
{
  "scripts": {
    "storybook": "start-storybook -p 9001 -c .storybook"
  }
}
  1. 更新 .storybook/config.js 为以下内容
import { configure } from '@storybook/react';

function loadStories() {
  require('../src/components/stories/Example.js');
}

configure(loadStories, module);
  1. 创建文件 src/components/stories/Example.js 并写入以下内容
import React from 'react';
import { storiesOf } from '@storybook/react';
import Example from '../Example';

storiesOf('Example', module)
  .add('normal', () => (
    <Example />
  ));

然后就可以通过 npm startnpm run storybook 分别运行项目和 Storybook。

开发流程


引入 Storybook 后,在本地开发时,需要同时运行项目与 Storybook。然后组件开发,测试工作都先在 Storybook 中完成,再把组件接入项目系统中联调。流程如下:

image

在一个隔离的环境中开发组件,自然就能保证组件不与上层代码耦合。

除了上文提到的优点,引入 Storybook 还带来了额外的好处:

  1. 组件 debug 会变得简单。

当一个组件碰到问题时,先尝试在 Storybook 及业务系统中分别重现问题。 如果 Storybook 中无法重现,在业务系统中却能重现时,那么问题大概率是在组件的使用方式上。以此类推。
  1. 使用 Storybook 开发组件时编写的 stories 也能成为组件的使用示例,一定程度上缓解了业务代码缺少文档的问题。