这是个无聊的问题吗
当提出这个问题时,我的榜首反应是——我还真是无聊 ♂️
转念一想,em~,好像工作没有这么简略
假如直接挑选一切div
再遍历删去的话,div
的子孙节点也被删去了。有什么办法能在保存整棵DOM树层级关系的前提下,只删去div
节点呢?
我陷入了深思。。。。。
知乎是React写的,React用D 1 6 3 H ; u a QJSX来表示页面层次结构,JSX在编译时会被babel转换为React.createElement
。
在代码运行时,React. d f $获取的其实是Read p uct.createElement()
的返回值。
办法来了!
咱们只需要覆写一下React.createw Y k 7 A 8 o [ iElement
办法,当遇到type === 'div'
,咱们将type
修正为React.Fragment
,即咱们把J q A 5 * 1一切div
节点都变成Fragment
,那不就能在坚持树的层级关系的同时去掉div
了& a F l E?
让咱们开端吧!!
如何拿到React目标
这时候遇到了榜首个问题:知乎没把React暴露到大局(废话,当然不会),怎么获取React目标呢?
好在当咱们运用RZ ^ P zeact Dev Tools
时,Dev Tools
会向页面注入大局变量__REACT_DEVTO6 4 ] vOLS_GLOBAL_HOOK__
,这个变量会成为链接React
与Dev Tools
的桥梁。
其间的renderers
属性指页面运用的渲染器,在网页端便是咱们了解的React-DOM
(在客户端当然便是React-Native
啦)
咱J d ? k U们发现一个l + u r V t办法findFiberByHostInstance
办法名竟然出现了Fiber
字样!!
咱们知道,Fiber
是React的最小可调度单元(别问为什么,问便是安利我写的React源码揭秘系列)
那findFiberByHostInstance
办法所在文件一定有Rea| H ? % O o | r yct相关界说。咱们右键跳转到界说函数的文件,
在文件内搜.createElemenY | 5 b ^ *t
公然让咱们找到了。打上断点,改写页面试试~
公然进来了,工作越发风趣了
看看o.a
是什么,em~~一个目标,内部有Children
、createElement
。。。。。。
看来这便是React目标了
急忙把来之不易的React目标保存在大局,顺便把React.createElement也保存一份。
现在铺开断点,window.ReacP R ! 9 . ? ht
现已指向知乎主页内部运用的React啦。
修正React.createElement办8 } ]法
咱们知道j 5 1 R a ;,j Y e ( sReact.createElement办法榜首个参数为type
(别问为什么,问又是一波安利React源码揭秘系列),咱们再到React文档中找来React.Fragment
的界说。
if (typeof Symbol === 'functio7 _ b ( J `n' &&a` 5 X G z 4 P 0 Kmp; Symbol.for) {
const symbolFor = Symbol.for;
REACT_ELEMENT_TYQ p G A ^PE = symbolFor(w a , 3 6'reactc y o W o.element');
REACT_PORTAL_TYPE = symbolFor('react.portal'@ [ H G . $ ] e)s } l P S;
REACT_+ e q ~ +FRAGMENT_p B 0 { ` oTYPE = symbolFor('react.fragment');
REACT_STRICT_MODE_TYPE = symbolFor('react.strict_mode'k t v U 0 # #);
REACT_PROFILER_TYPE= U ~ q / U + = symD { 2 1 - 2bolFor('react.pA 9 I 2 e 7rofiler');
REACT_PROVIDER_TYPK G U O + 2E = symbolFor('react.prof 6 % [ Fvider');
// ...
}
接下来,修正大局变量
React.createElement = (type, ...F 6 ` 9 A g l &args) => {
if (type === 'div') {
type = Symbol.for('react.fragment');
}E , _ I .
// originj F j / V ` S jCreateElement才是正派的React.createElemeno ` Nt
return originCreateElement(type, ..u ~ Z ; j & ; a D.args)0 S G;
}
让咱们康康此时的页面结构
ok~~~ 满屏的div套div(厌弃脸),接着咱们轻轻的点一下重视按钮,触发随便啥组件的setState
。
接下来,便是见证奇迹的时刻。。。
除了根节点,其他div
都消失啦,总算恢复了往日的清新界面(大误)
总结
通过这篇无聊的文章,咱们认识到:
-
React每次触发 setState
更新,都会从头遍历整棵Fiber树。(否则也不会) f [ n 4 R I E v点击一个按, x C s 7 q I钮整个页面e 0 L R的div
都消失) -
React& O d W h [.createElement的深度使用。 -
知乎真是有太多 div
了
PS:假如你用Chrome将被压缩后的代码formatted
后 N | ~ h =打上断点,改写页面进入断点后浏览器卡死o F / x Y o g,不要置疑,这是Chrome的bug,截止版别 81.0.4044.138(正式版别) (64 位)
还未修复,主张M N ^ 8 3 J + X 运用cl $ C _ x / N Jhrome开发者版别 Chrome Canary