2个月的工作心得
之前失业了9个月,心里面的计划是一定要找react方向的,因为vue本身由于框架特性,使用简单,能够积累出的东西完全要靠业务, 而react本身由于框架特性,很多人写了很多年也没有完全理解如何优化渲染,这是一个比较深的问题。
工作内容
工作主要也是写业务的,在一个基于微前端的saas平台上开发业务。产品经理是准备做一个paas平台。 由于微前端的限制,框架版本基本不往上升级,不过还好是react 16.8.6,还是可以使用hooks的。antd是4.8.5。 但是坏消息是,看到了几个项目,都是class写的,不过还好我对于vue的hooks还是很熟练的,对于react渲染机制的理解有一点,影响不大。
基本上也会经常打印log来检测页面的渲染次数,通过优化来减少重复渲染的问题
工作目标
我最开始想做的是apiFox那样的前端库,基于配置请求参数和管理请求,与部分的业务重合了,而且我在github想搜有没有类似功能的组件库,但是发现都是以项目形式的,很少开源。 于是我想做一个,顺便做成npm包,也开源能让大家参考一下。
遇到问题
由于有些库的版本有点老,遇到一点小问题。主要问题目前是两个
1. antd的树的筛选功能,只是展开和折叠,没有办法过滤,因为apiFox的筛选,是只留下符合的,父级菜单也是要留下的。最早开始时构建树的过程,顺便构建索引,这样就可以顺着索引快速查找删除,没有做筛选。后面做筛选的时候,发现有点麻烦。
一开始,是不打算做麻烦的,想用antd的,通过titleRender
- 思路给树的节点打标签,不展示的增加一个class,父节点class通过has来控制display:none
- 做了一下,通过筛选的时候,对树所有节点进行递归,递到最后,判断当前title是否包含,
- 归的时候,将自己的状态和父的状态合并,自己显示,父亲也要显示,用||操作符
- 最后效果不太好,dom在大批量切换成display:none的时候卡顿很明显,不如完全树。
之后打算构建一个树在redux里,筛选无非重新构建一颗新树,没有筛选条件的时候,再还原回原树,但是发现在筛选时候产生的操作就有问题了。回到不筛选之后,之前的操作都消失了。
最后在redux搞了一个完全树,一个展示树,为了查询和遍历速度,额外构建了树的map和list,list中有每个节点的父keys
- 筛选时,从list里找到所有符合的,返回所有的父keys+自己的keys的string[][]数组
- 构建新树,顺着keys,从0开始找构建树是否已存在节点,不存在生成一个节点,插入上级的children,继续往下找
- 顺序是每个sting[] 从0,0-1,0-2,一直到0-length-1,遍历完所有数组,得到一颗新树
- 在筛选时候进行的操作,同时在redux原来的完全树上,找到key对应的节点,也要进行增删改查操作,同时对list和map也要进行,以防匹配不上,重新遍历效率肯定更低。
- 而且要注意的是,同样节点,可能有重复操作,进行完全树操作之前,判断是否是同一个节点,同一个节点就忽略。因为redux是浅拷贝,深层树有可能是同一个引用。
2. 多窗口的性能问题,我在打开窗口,在redux中存的是keys,渲染的时候,先去apiMap中找,没有就new一个,因为其中涉及到配置参数和body还有Response的jsonschema解析,每次点一下,得等接近1s
- 不断的打log,尽量减少重新渲染的问题,还有靠console.time和timeEnd来看消耗的时间,但是数据解析消耗的时间并不长,应该是渲染的时间久。
- 发现react,渲染规律是自顶向下的,页面的重新渲染主要靠props和state
- 外部props导致的重新渲染。通常不会考虑太多,因为props基本上都是要用才传递的,方法是不会导致重新渲染的。
- 极端情况下考虑使用memo或者早期的shouldUpdate来减少prop导致的重新渲染
- memo并不是银弹,用memo的时候一定要清楚你的页面渲染的底层逻辑是依赖哪些props
- 使用memo之后,传递props页面很要注意,尤其是reducer操作,不要修改reducer再返回,需要直接返回新的reducer,
- 例如数组删除和修改,最简单就是splice(index,1)和到索引里改arr[index]={…},然后return[…],但是这样会导致前后props是一致的。页面不会重新渲染的。
- 内部state导致的重新渲染。大组件的话,任何state改变都会导致重新render
- 将setState的操作抽离单独组件,隔离对其他children的影响。因为父组件影响,基本上子组件也会重新渲染,可以参考上面的props优化
- 对于一些很确定不会重新渲染的,加上不变的key来控制。
- 对于预期不怎么会变的值,使用ref来接收值,ref变了也可以传递的,
- 有时候,无论怎么都会触发到组件的render,例如全局的addListener的click点击事件,要设定一个阈值,不改变的时候不要影响渲染。
- 对了非react合成事件中,例如addEventListener的函数中是没法访问state的,建议使用ref或者直接传递参数。
- 也不要畏惧重新渲染,预知页面的渲染开销,正常从上往下过一遍不会影响很大,useMemo也只是那一块用在fiber的缓存罢了。
- 外部props导致的重新渲染。通常不会考虑太多,因为props基本上都是要用才传递的,方法是不会导致重新渲染的。