Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Hook、Models、Plop #37

Open
jsonz1993 opened this issue Dec 27, 2021 · 0 comments
Open

React Hook、Models、Plop #37

jsonz1993 opened this issue Dec 27, 2021 · 0 comments

Comments

@jsonz1993
Copy link
Owner

本文主要记录最近工作中对Hook、数据模型和plop工具的探索

React Hook编写范式

在React16 hook刚出来的时候,其实就有尝试过在项目中使用hook的经历,但是当时给我的感觉是,没有class便捷,而且代码组织很混乱,容易变量满天飞,再加上一个组件写起来经常会超过上千行代码(class component的思维)。写出来的代码也容易有一些变量监听混乱的问题,所以后面在小的组件才会用fc,而在页面级别的组件还是传统的class component。

其实我们在写组件的时候,只需要区分好实现的细节和逻辑的节点就好,class之所以看上去会比较有条理,是因为天然的把这些逻辑都写在一个成员函数里。类下面的每个成员函数代表一个处理的细节,编辑器中直接把代码折叠后,就会发现class写的比较有条理,想找什么细节直接点开去找。

FC或者hook也是一样的,举最近做的一个 新建/编辑签署页为例,提取简单的业务逻辑节点。

  1. 确定页面是新建还是编辑
  2. 编辑页需要根据paperNo去请求数据填充,新建页则做一些初始操作
  3. 提交、保存、确认、取消等操作
  4. 其他行为,比如自动保存草稿与恢复编辑草稿等
    所以我们的组件大概可以是这样
function SignoffForm() {
  const [initState] = useInitDataWithState()
  const [handleSubmit] = useSubmit()
  const [hasDraft, {
    removeDraft,
    fillDraft
  }] = useAutoSave()
  
  return (
    <form> ... </form>
  )
}

虽然不一定这些hook是可以被复用的,但是这样抽离出去,整个组件的逻辑就清晰很多,别人来接手看代码的时候一看就知道这个组件大概的功能点在哪。想要改某个功能点的时候再去看实现的细节,比如说初始化数据的时候有bug,那直接去看 useInitDataWithState 这个hook就可以,不需要在一大堆意大利面里找代码。

而里面的一些逻辑抽离成hook之后还可以和其他的组件复用,比如 送签表单需要草稿功能,付款表单也需要草稿功能,那 useAutoSave 就可以直接在两边都用了,这在 class Component 里面是无法想象的。

再者比如最近在做一个公益的小程序,用的框架是Taro,如果在pc或app端用Hook实现了一些逻辑的话,那么在小程序上也是可以直接拿来就用的,比如ActionSheet有展示和隐藏的逻辑,那是不是可以直接用 useToggle 来管理这个状态切换呢?

这和数据模型有点共通之处,现在在项目中,会把业务模型抽离出来独立于框架,这样后面换个vue或angular框架,内部的业务逻辑也可以直接共用,同理还有headless component。其实最近在工作的时候都有很留意headless的思想,因为项目即将进行大范围的重构,这些脱离UI的逻辑实现后续复用起来会更方便。

回到Hook上面来,现在一般页面的组织形式如下:

signoffForm
├── components 当前页面的组件
│   ├── field.jsx
│   ├── formItem.jsx
│   ├── index.js
│   ├── oppositeCorporations.jsx
│   ├── oursCorporations.jsx
│   └── selectFormItem.jsx
├── helper.js  与UI、State无关的函数,一般是数据转换
├── hooks.js  页面相关的逻辑,实现细节抽离成Hook
├── index.js
├── model.js  Redux model
└── signoffForm.less 样式表

shared
├── models
│   └── signoffModel 送签模型,负责处理送签各个字段的逻辑,比如必填,展示,字段关联等

多端统一数据模型

在我所在的项目组里由于是投资领域的2B业务,平时主的工作是数据处理,业务逻辑,各种字段的关联关系,表单处理等,比较少接触动效领域。
工作中会发现很多字段的处理逻辑其实是一致的,比如一个字段format是四舍五入还是小数点后六位直接舍去,单位是需不需要用mn,bn,tn等,这些处理方式在列表页、详情页、表单页其实处理的逻辑都是一致的。
再或者比如一个表单字段,可能需要 name、default、label、type、validator、optionKey、optionValue、placeholder、hidden、drop等等十几配置信息去描述他,这些以往我们可能都是直接写在jsx里面,比如:

<form-field name="category" default="" label="文件类别" validator="required(xxx)" optionKey="type" optionText="name" .... />

pc这些写,app也这么写,后面改的时候又得两处改,更关键的是,如果多端因为历史债务原因使用不同的技术栈,那么端与端之间的复用更是无从说起。

所以最近在做项目的某个业务时,转换一下思路,将字段的逻辑抽离成一个model,脱离技术栈的实现。有点像DDD,在写业务之前先思考这个模块到底涉及了哪些逻辑,哪些字段,这些字段与字段之间的关系是什么,然后单纯用js来描述这些属性。
最后再写一个桥接,将这些model和view映射起来,比如react,那可能就是变动的时候触发setState更新视图。

这么写的好处是什么?
将这些复杂的业务逻辑抽离出view层,不仅在angular和react可以复用同一套业务逻辑,后面重构的时候,也可以最大程度的复用这些代码,只要是能跑js的都能运行。
业务变动的时候也不会改一个端之后忘了修改另一个端,如果只是样式变动则只需要修改某个端的ui呈现。
其实这块就是对应上面 React Hook编写范式 中的 shared > models > signoffModel

class Demo1 extends BasicMeta {
  static name = '示例文案'
  static default = ''
  static label = i18next.t('signoff:demo')
  static type = Number
  static formValidator = required(Demo1.label)
  static optionKey = 'type'
  static optionText = 'name'
  static valueType = 'key'
  static fieldOptionsKey = 'demo1'
  static placeholder = generatePlaceholder(Demo1.label)
  static hidden() {
    return !isCNY(this.team)
  }
  static drop(data, key) {
    return this.$views[key].hidden
  }
} 

利用 plop 规范化代码模板

最近做项目的构建工具时,顺手加了一个 plop 功能, plop 官方的描述是: Consistency Made Simple。

简单来说我们可以利用它做一些项目中的模板生成,比如 components pages modules 的生成。这里有个很简单的示例 plop-demo

git clone [email protected]:jsonz1993/plop-demo.git
cd plop-demo 
npm i
npm run start
// 新开一个shell
npm run new 

如果我们选了modules 并输入modules 名,可以发现工具自动帮我们把modules的模板拷贝的对应的位置,并且修改了路由文件。这只是一个简单的实例,在项目中我们的模板会更加具体,路由器及其他相关配置也会更多,这块可以继续看官方文档。https://github.com/plopjs/plop

plop-demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant