起因
初出茅庐的我一猛子扎进React的海洋,挣扎的过程中可谓使劲浑身解数,只要是React文档中有提到过的,无所不用其极。最后,在前辈的熏陶还有编写项目和自我学习中,规范性也越来越强,思路也越来越清晰——狗刨终于进化成自由泳。
这篇文章中呢,起因就是在实现一些需求的时候,通篇React语法中加入了古老的DOM读写,然后就被老大批评了。青少年最不缺的就是锐气和钻研精神,哈哈,没错,写这篇文章最大的原因就是——我不服~
为啥不让我用DOM?DOM有什么不好?React很难实现的需求应该怎么做?
结果
没错,结果就是——服。在经历许多代码重构和逻辑修改后,发现React中有个DOM从视觉上感觉就有些不爽,不加上注释或者即使加上注释都给人一种不知所谓的感觉,维护上也有很大难度,比如
if (this.tableIsOpen) { // 表格自展开 setTimeout(() => { const openClick = document.querySelectorAll('.testToggle'); for (let i = 0; i < openClick.length; i += 1) { openClick[i].click(); } },10); }当然最主要的是性能,因为React在DOM二次渲染时的效率会比原生DOM的效率高的多,所以会有更好的方式去解决。下面就来具体的说一下。
过程
用DOM的场景
1、在已有组件的基础上,待组件渲染完成后,调用其内部的方法。比如uxcore-table实现二级表格自展开时,需要调用组件元素中绑定的
toggleSubComp(rowData)
。
2、DOM获取document.body.className
来判断国际化环境是否为中文。
3、多个组件,一个组件的状态需要保持不变,但是其他组件需要根据交互来改变状态。例如
<Father> <brother> <child></child> </brother> <notChange></notChange> </Father>
可优化方案
1
首先说第三个场景,说到改变状态当然就是
state
和setState
,那么顺着这个思路走的话,好的,分割好每个组件,各个组件的方法最好不能有交叉。
然并卵,一旦各个组件之间有了交互上的关联,状态改变条件互相依赖,即使让各种props
穿插传递状态条件,但是,props
的变化对于需要接收它的组件,componentWillReceiveProps(nextprops)
在父级有变化(setState
)时,才会接收新的props
。完蛋,又回到原点,需要保持状态不变又与需要变化的组件有交互关联的还是要被setState
影响。
所以,用DOM吧。。。但是,用DOM修改元素,是很影响性能的,下个小结会说。其实这个思路其实并没有错,这个时候就要用到react专门为一些特殊情况准备的refs,官方文档上说:ref添加到Compoennt上获取的是Compoennt实例,添加到原生HTML上获取的是DOM
When attaching a ref to a DOM component like <div />,you get the DOM node back; when attaching a ref to a composite component like <TextInput />,you'll get the React class instance. In the latter case,you can call methods on that component if any are exposed in its class definition.
这个意思,就是我在自己的class xxx extends React.Component
的组件上加上refs
中,获取的是虚拟DOM节点(ReactElement),那么,就好说了,再也不用乱搞一气的props
还有原生DOM的一堆改变样式的操作,在组件内部写方法,然后根据父级状态条件,利用this.refs.xxx.fn(status)
调用即可。
2
第二个场景,个人感觉并没有影响到性能,毕竟React的组件在
<script></script>
标签中,浏览器解析html的时候,在React的组件加载前,<body></body>
元素已经存在,单纯的查询DOM不会导致页面的重写和回流。所以个人认为,React中还是可以少量用一些无关痛痒的DOM(我会说我还是钟爱原生DOM吗)。
3
第一个场景,最开始举的例子。用于
componentDidMount
中,哈哈,死循环——在展开二级表格时不断的从新渲染继而不断调用该方法,那么用在componentDidUpdate
中就可以了,但是为什么要用定时器呢,因为在元素节点全部渲染出来时,只会在最后一个元素执行点击事件,用refs也是一样的。
目前还没有找到原因,探索中。。。如果有大大知道,可以告诉我啊~不胜感激^ο^
DOM影响React性能分析
对于性能的影响,很明显了,就是多余的DOM计算。既然React用的虚拟DOM形式,再用DOM去修改,那么,浏览器再计算全部React的更改后,再去计算一遍原生DOM修改,这就非常尴尬了,React还不如不去用,也没有节约多少时间。
再次整体用React中穿插DOM看着也不是很美观。
总结
在应用一个框架的时候,那么,我们不但要理解它的思想,还要严格的执行它,当然这个思想必须是正确的,高效的。比如React的虚拟DOM,就要在虚拟DOM中操作。如果代码不遵循它的思想,那么就相当于不承认这个框架,这种冲突如果出现,要么重构代码,要么就摒弃这个框架。以上是本人这个小前端的一点经验和浅见,希望大家给予指正~