基于react的表单类页面复用思考

前言

很久之前,我用vue重构过部分表单类页面的代码,主要实现了表单类页面里函数与数据复用的问题,当时实现的方式是以类的方式构建表单类,而表单页面的数据和表单页面的方法一并捆绑在一个类里。优化效果是表单类页面中减少了很多使用函数修改数据的代码。
后来,我接触到了react,发现,原来表单类代码的优化,是不止步的!

面向页面编写->面向页面的组件编写

思路转变一:接触react有个重要的思维转变—一切即组件
改变:ui的大规模复用

(好吧我承认是之前vue学习不够深入,连vue的jsx都没用…)
言归正传,由于react的jsx,我们可以实现很多ui层面的代码复用。
比如之前的原始订单,我可能因为销售订单页面某地方比原始订单多了一个按钮就需要将原始订单的所有ui代码都拷贝过来,然后在相应位置加个按钮(以页面一个最小单位的背景下,即未使用组件化思想)
然而现在,things changed!

以最最常用的表单类页面为栗子,现在将页面分为多个组件拼凑而成,就像搭积木一样。
我们还是以页面为一个单位集,但是一个页面由很多组件组合而成。如典型的表单页面我们划分为顶部筛选组件filter、中间列表list组件
这里写图片描述

先看下我们要实现的效果:
原始订单
这里写图片描述
销售订单
这里写图片描述
比较下:
两个页面几乎一摸一样,不一样的地方就是标号1代表的toolbar栏,个数及方法等不同;其次标号2的筛选框不同。
我们现在将页面按功能区拆分为各组件之后就能实现3、4的复用(至少)

数据与ui分离

复用ui层面的代码的前提是(一个重要的转变是),让ui组件只专注ui,并不关注怎么获取数据,以及数据怎么来。一句大白话解释就是其他组件给了我数据,我只管接着便是。而我响应用户的操作,也并不亲历亲为地去拿数据,我只需要对着天空大声地呼唤:我发出了XX动作,自然会有相应响应(数据等)注入你的组件层面。

现在我们写好原始订单的4大类,而再次创建销售订单时我们只需要写不同的1和2组件即可.
总结下:
销售订单和原始订单共享受一个list组件,list组件里定义好了表头展示的文字及对应数据的字段,因为销售订单和原始订单需要展示的数据一摸一样(表头字及字段名),所以在此基础上实现了ui组件list的复用。
而上升到页面级容器组件-销售订单和原始订单他们做了什么呢?
负责接收外部的数据(表现是每个订单数据[多少]不一样,实际上是调用请求的接口不一样),然后将接收的数据做为props注入list组件,这也是为什么ui与数据分离这个新思想这么有用的原因。
至此,我们得出相较以前实现方案取得的巨大进步:
ui复用(得益于ui与数据分离 及模板引擎的功效)

回归本质思考—复用的最大阻碍

而到了容器层,我们发现还是存在几乎相同的函数只是调用不同的后端api获取几乎相同的数据,我们却要因为不同url和不同页面级组件(在我看来就是后端调用api和页面级组件的名称不同而已)的问题,几乎全部重写整个代码(dispatch到调用方法获取数据的)流程

这一点无论是我换了几种复用思考方式都避免不了的问题,表单类页面本来就有很多相似之处,以前思想停留在怎么让页面少写点长的差不多的函数(函数公有化),或者干脆以页面为单位公有化(类),以及刚才的页面拆分组件颗粒化(拼接式代码复用),而但当我们走了这么多路才发现,针对标准crud表单页面来说,真正的重复是体现在:不同页面相似展示,只是请求的url不一样的问题【原来你是大boss啊

思考:

一、toolbar的按钮触发事件优化:
顶部那一行toolbar中的上张下账审核等,我是一个按钮对应一个函数,触发一个事件。
最刚开始的思考是:上张下张能不能合成一个事件?因为他们的操作几乎一摸一样:
这里写图片描述
只是url不同,甚至只是url的某一段不同
再深入思考:toolbar的那一排顶部按钮们能不能用一个click事件监听呢?根据按钮值响应不同函数?

二、关于相似页面复用的思考:
无论我换了用什么框架,应用从框架中接触到不同思维可以使得看似使用每个框架都能减少不同程度或不同方面的冗余代码(或方法数据重用,或组件颗粒化实现组件级别复用或最刚开始的提公有函数),真正写下来反思会发现之前的代码优化都是”有点治标不治本”,因为这种很普遍的增删查改表单类页面真正重复的本质是:不同页面对应不同后端api而响应不同数据。即不同的页面与后端api
所以我就在想,能不能写个通用的,以组合的方式写个最最最普通的页面级组件,有增删改的页面组件,这个页面级组件抛开具体的业务逻辑。就是请求不同api拿到不同数据,进行展示。

小实践

思考一的实践:

在jq中:我们使用事件委托机制即利用冒泡原理,将事件绑定到节点的父级节点上,从而触发这些节点执行代码中编写的效果;
react:事件机制
react里toolbar都是自动生成的利用一个onClick函数解决,这得益于react的事件机制(react中的事件对象不是原生的事件对象,而是经过处理后的对象)
详参:https://segmentfault.com/a/1190000008596587

思考二实践:

感谢高阶组件的理念,每次实践遇到困境再看官方文档真的会有新发现..

灵感来源于官方文档高阶组件的相关栗子,这里我简述下我理解的高阶组件的相关知识。
1.基本概念
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件
所以高阶组件可以为输入的原始组件增加新的功能,也非常适合处理一些每个组件都需要去做的重复性工作,比如获取数据并将获得的数据传递下去
即高阶组件封装并抽离组件的通用逻辑,让此部分逻辑在组件间更好地被复用,同时也能抽离或组合公共的ui组件(可以理解为一个公共类)

2.基于属性代理和基于反向继承
基于反向继承

这种方式返回的react组件继承了被包裹的组件(父类组件返回的组件继承子组件 所以叫反继承),
为啥反继承? 正因为反继承所以可以访问的区域数据更多 甚至可以修改被包裹组件的内部状态
渲染劫持:HOC可以拿到包裹组件的state和props进行修改,从而改变组件的行为

常见应用:Loading组件作为高阶组件 需要拦截子组件的渲染过程,

基于属性代理
无需改变子组件内部的展示方式,只在外围增加功能 则属性代理 如复制组件,高阶组件操控传递给 WrappedComponent 的 props。使用属性代理的好处就是,可以把常用的方法独立出来并多次复用。比如我们实现了一个加法函数,那么我们把加法函数改造成形如上述HOC函数的形式,之后对其他组件进行包裹,就可以在组件里使用这个方法了。

3.高阶组件与父组件区别
高阶组件作为一个函数,它可以更加纯粹地关注业务逻辑层面的代码,比如数据处理,数据校验,发送请求等,可以改善目前代码里业务逻辑和UI逻辑混杂在一起的现状。

思考

list页面保留,我们将toolbar一栏(每个页面都会有的一堆操作按钮[只是值不一样])放进高阶组件进行组合加工,高阶组件接收list组件返回toolbar组件+list组件组合而成的完整的页面。
并且实现属性代理,即用户对toolbar的操作会在高阶组件得到响应,并将得到的响应数据从高阶组件为起始传递给list组件

这样做的好处是什么呢?
1.toolbar做为公有方法,被分离复用了
2.调用不同api返回不同数据注入不同的页面且使用一个函数成为了可能。

不信你看:
在高阶组件里,toolbar的click事件根据不同的按钮类型对应有不同的函数修正响应值this.state,
而注入list组件的props数据正是state里的originList
这里写图片描述
这里写图片描述

其次最关键的问题:高阶组件包裹了那么多不同的组件,它是怎么判断当前系统是哪个页面级的组件调用了公有的toolbar方法呢?而它又应该如何实现方法的实际公用呢?
解决办法:
1.被包裹组件传参给高阶组件
其实还有更巧妙一点的办法,即拿后端接口的页面关键词做为组件名,高阶组件直接获得被包裹组件的名字即可拿着页面级字段去调用后端接口
2.思路就很明显了,我们的toolbar方法接口应该”写活”

这也算是一个重要的思维转变吧,以前定义一个函数都是按照页面为单位(方法被限定在一个页面内),现在是一个方法对应不同页面准确说是不同的url(方法站起来了!)。

这里写图片描述
调用:
//这里只简单实现了获取页面最大最小id
这里写图片描述

总结
虽然这样能在高阶组件里通过toolbar的函数方法改变state值直接将state传入props使得l表单类也页面复用提高,但是感觉怪怪的:其一代码写的有点五花八门丑陋了点,其二,在dva的数据管理中显得那么格格不入。当然这对于练手的思考demo,我觉得我还是有所进步

(后话)我想说的是,关于表单类的编码思考远远没有结束..

猜你喜欢

转载自blog.csdn.net/young_Emily/article/details/79427913
今日推荐