偷懒不可取:React中DOM

起因

初出茅庐的我一猛子扎进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

首先说第三个场景,说到改变状态当然就是statesetState,那么顺着这个思路走的话,好的,分割好每个组件,各个组件的方法最好不能有交叉。
然并卵,一旦各个组件之间有了交互上的关联,状态改变条件互相依赖,即使让各种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中操作。
如果代码不遵循它的思想,那么就相当于不承认这个框架,这种冲突如果出现,要么重构代码,要么就摒弃这个框架。
以上是本人这个小前端的一点经验和浅见,希望大家给予指正~

    原文作者:远远的飞梦
    原文地址: https://segmentfault.com/a/1190000009020774
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞