起因
初出茅庐的我一猛子扎进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中操作。
如果代码不遵循它的思想,那么就相当于不承认这个框架,这种冲突如果出现,要么重构代码,要么就摒弃这个框架。
以上是本人这个小前端的一点经验和浅见,希望大家给予指正~