为了账号安全,请及时绑定邮箱和手机立即绑定

React就是加了包装的document.createElement(),我来给你证明这一点

经过15年的 web 开发,我有了一个令人震惊的觉悟:现代 Web 开发界的宠儿 React,只不过是被精明的市场包装和日益复杂的抽象概念所包裹起来的 document.createElement()。我将向大家证明这一点。

Emperor的新衣

我们先来看一个简单的例子。这里演示如何用纯JavaScript创建一个标题(heading):

const heading = document.createElement('h1')  
heading.textContent = '大家好'  
heading.className = '问候语'  
document.body.appendChild(heading)

这才是React的现代做法:

const Heading = ({ 文本, className }) => { 
 return <h1 className={className}>{文本}</h1> 
} 
// 示例: 
<Heading text="Hello World" className="greeting" />

但是等一下!你可能会说:“React 提供了可复用的组件!”没错,这是它的原生版本:

function createHeading(text, className) {  
 const heading = document.createElement('h1')  
 heading.textContent = text  
 heading.className = className  
 return heading  
}  
// 用法示例:  
document.body.appendChild(createHeading('Hello World', 'greeting'))
抽象的兔子坑

但是情况变得更好了。我们来看一个最近在一个“现代”的代码库中遇到的真实世界的React 组件:

    <TypographyProvider theme={myTheme}>  
      <TextContainer variant="primary">  
        <Typography   
          component="h1"   
          variant="heading"   
          size="lg"  
          color="primary"  
          fontWeight="bold"  
          className={styles.customHeading}  
          >  
          你好,世界  
        </Typography>  
      </TextContainer>  
    </TypographyProvider>

这一切……只是为了渲染一个 <h1> 标签。这根本不是组件复用;纯粹为了抽象。我们从简单的 DOM 操作变成了套娃式的组件结构,每一个组件都增加了自己的复杂性层次、打包大小以及潜在的故障点或问题。

但是虚拟DOM呢

啊,没错,就是React的瑰宝——虚拟DOM。它被宣传为一种革命性的性能改进,但让我们实话实说:这个问题是我们自己制造出来的,因为我们使组件模型过于复杂了。我们实际上是说:“有了我们自己解决方案导致的问题的解决办法,而这些问题大多数都是我们自己想出来的。”

TypeScript '负担'

为了更清楚地说明这一点,让我们来看看当我们引入TypeScript时会发生什么的情况。

    interface TypographyProps extends HTMLAttributes<HTMLElement> {  
     component?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';  
     variant?: 'heading' | 'body' | 'caption';  
     size?: 'sm' | 'md' | 'lg' | 'xl';  
     color?: 'primary' | 'secondary' | 'error';  
     fontWeight?: 'normal' | 'bold' | 'lighter';  
     className?: string;  
     children: ReactNode;  
    }  
    const Typography: FC<TypographyProps> = ({  
     component = 'p',  
     variant = 'body',  
     size = 'md',  
     color = 'primary',  
     fontWeight = 'normal',  
     className,  
     children,  
     ...rest  
    }) => {  
     const Component = component;  
     return (  
       <Component   
         className={clsx(  
         styles[variant],  
         styles[size],  
         styles[color],  
         styles[fontWeight],  
         className  
         )}  
         {...rest}  
       >  
           {children}  
       </Component>  
       );  
    };

这都是为了展示一个带有文本的HTML元素。

不顺风税

趁着我们现在在这里,我们来谈谈 Tailwind — 因为写 CSS 类好像太难了,所以现在我们写内联样式,假装它们就是 CSS 类。

    <div className="flex flex-col items-center justify-between p-4 m-2 bg-blue-500 hover:bg-blue-700 text-white font-bold rounded transition-colors duration-200">  
      你好,世界  
    </div>

还记得我们曾经批评过内联样式吗?现在我们只是把它们变长,并称其为样式框架,而不是我们没有改进它们。

    .button {  
      /* 显示为弹性盒子 */
      display: flex;  
      /* 设置弹性盒子的方向为竖直排列 */
      flex-direction: column;  
      /* 使项目在主轴方向上居中对齐 */
      align-items: center;  
      /* 在交叉轴方向上将项目间隔均匀分布 */
      justify-content: space-between;  
      /* 设置填充区域 */
      padding: 1rem;  
      /* 设置外边距 */
      margin: 0.5rem;  
      /* 设置背景颜色为蓝色 */
      background: blue;  
      /* 设置字体颜色为白色 */
      color: white;  
      /* 设置字体加粗 */
      font-weight: bold;  
      /* 设置圆角半径 */
      border-radius: 0.25rem;  
      /* 设置背景颜色过渡时间为0.2秒 */
      transition: background-color 0.2s;  
    }  
    /* 在鼠标悬停时 */
    .button:hover {  
      /* 设置背景颜色为深蓝色 */
      background: darkblue;  
    }

我们遇到一个单行的 CSS 错误,这个问题让文本超出自1995年以来制造的每一台显示器的右边界。但至少我们不用再写 CSS 了!我们只是在写……更长的内联 CSS……打更多的字。

真正的成本

这种复杂性带来了实际的成本:
- 更复杂的构建流程,
- 更高的理解成本,
- 新开发人员上手更难,
- 层层嵌套的依赖关系,
- 更大的包体积,
- 更多的故障点。

为什么呢?

真正的问题是:为什么我们要接受这一点?答案在于以下几种因素的完美风暴:
- framework marketing
- 简历驱动开发
- 编筐文化编程
- 错误地认为更多的抽象总是意味着更好的代码

一个小小的建议

这里是我大胆的建议:也许,仅仅是也许,我们不需要用三层组件包裹每一个HTML元素。也许document.createElement()并不是我们应避开的东西。也许我们不需要假装DOM不存在。

不可避免的网络骂战

我已经能想象到一些回应了:
- “但是状态管理呢?”
- “组件生命周期呢?”
- “我该怎么处理复杂的UI更新?”

对此,我的回应是:我们是怎么在没有 React 的情况下,几十年来搭建出这么多复杂的 web 应用程序的?难道这些应用都是我们凭空想象出来的吗?

内容生产工厂依旧忙碌

谈到用抽象概念掩盖现实,我们来聊聊你大概在哪里看到这篇文章。Medium 已经变成了一片荒漠,充斥着在不同标题下重新发布的 AI 生成的文章,每一则都承诺揭示“React 性能的 10 个 SECRETS”或“每个高级开发人员必须知道的 5 种 PATTERNS”。

这是一样的浅薄内容,通过不同的标题进行重复利用,每个标题都为了吸引更多的点击而优化,但却没有什么新内容。就像我们的排版组件通过层层抽象包裹基本的HTML一样,这些文章也将同样的陈旧的想法包裹在层层点击诱饵的标题中。

用AI来写这篇批评真讽刺,不过至少我说出了实话,你们的保费可是支付了这笔费用的。

最后,我们来总结一下

React 并不是那么糟糕。它解决了真实的问题,并引入了一些真正有用的模式。但在某个阶段,我们偏离了正轨。我们将简单的 DOM 操作当作是极为不好的事情,导致了越来越复杂和繁冗的抽象,却解决了一些想象中的问题,反而带来了新的实际问题。

下次当你准备使用一个组件抽象的时候,问自己:我真的在让这变得更好,还是我只是在给 document.createElement() 打了个漂亮的蝴蝶结呢?

[作者注:我已经因为愤怒的回复而焦头烂额了,但我的保险代理人说我还需要更多的证据来证明这是有预谋的。请尽量广泛地分享这篇文章。]

— -

我是一位高级资深架构师,擅长以各种方式在屏幕上呈现DOM元素,已有15年的经验。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消