
React 就是 document.createElement() 加上良好的营销手段,我可以证明这一点
2025年2月1日
经过15年的Web开发,我终于意识到了一个令人震惊的事实:React,现代Web开发的宠儿,不过是被包装得极好的营销策略和日益复杂的抽象层层包裹的“document.createElement()”。而我,将用实际行动来证明这一点。
皇帝的新部件
让我们从一个简单的例子开始。以下是如何用原生 JavaScript 创建标题:
const heading = document.createElement('h1')
heading.textContent = 'Hello World'
heading.className = 'greeting'
document.body.appendChild(heading)
以下是“现代”的 React 方式:
const Heading = ({ text, className }) => {
return <h1 className={className}>{text}</h1>
}
// Usage:
<Heading text="Hello World" className="greeting" />
“但是等等!”我听到你在喊,“React 为我们提供了可重用的组件!”是的,这是原始的等价物:
function createHeading(text, className) {
const heading = document.createElement('h1')
heading.textContent = text
heading.className = className
return heading
}
// Usage:
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}
>
Hello World
</Typography>
</TextContainer>
</TypographyProvider>
所有这些……都是为了渲染一个 `<h1>` 标签。这不是组件复用;这只是为了抽象而抽象。我们已经从简单的 DOM 操作变成了一堆组件,每个组件都增加了自身的复杂性、包大小和潜在的故障点。
“但是虚拟 DOM 怎么办?”
没错,虚拟 DOM —— React 的镇店之宝。它被誉为革命性的性能优化,但说实话:它解决的是我们最初让组件模型变得如此复杂而造成的问题。我们实际上是在说:“这解决了我们之前只存在于脑海中的问题,而现在我们却想出了解决方案,从而解决了性能问题。”
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">
Hello World
</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;
transition: background-color 0.2s;
}
.button:hover {
background: darkblue;
}
我们犯了一个单行 CSS 错误,代码长度超过了 1995 年以来所有显示器的右边距。不过,嘿,至少我们不用再写 CSS 了!我们只是在写……更长的 CSS……内联……而且需要更多按键。
真正的成本
这种复杂性会带来实际成本:
- 更大的捆绑尺寸
- 更复杂的构建管道
- 更高的认知开销
- 更多故障点
- 新开发人员的入职培训更加困难
- 依赖依赖依赖依赖
但为什么?
真正的问题是:我们为什么要接受这一点?答案在于:
- 框架营销
- 简历驱动开发
- 货物崇拜编程
- 错误地认为更多的抽象就等于更好的代码
一个温和的建议
我的激进建议是:也许,只是也许,我们不需要把每个 HTML 元素都包裹在三层组件中。也许 `document.createElement()` 不是敌人。也许 DOM 不是我们需要假装不存在的东西。
不可避免的口水战
我已经听到了这样的回应:
- “但是状态管理怎么办?”
- “组件生命周期怎么样?”
- “我将如何处理复杂的 UI 更新?”
对此我的回应是:在 React 出现之前的几十年里,我们是如何构建复杂的 Web 应用的?难道 2000 年代和 2010 年代初期的那些 Web 应用,我们只是凭空想象出来的吗?
内容工厂持续运转
说到抽象掩盖现实,我们来聊聊你可能在哪里找到这篇文章。Medium 已经变成了 AI 生成文章的荒地,这些文章被以不同的标题转发,每篇都声称要揭示“React 性能的 10 个秘密”或“每个高级开发人员都必须知道的 5 个模式”。
内容千篇一律,千篇一律,标题千篇一律,每个标题都力求最大化用户参与度,却毫无新意。就像我们的 Typography 组件将基础 HTML 层层抽象地包装起来一样,这些文章也用层层标题党的噱头包装着千篇一律的重复内容。
我当然明白用人工智能来写这篇批评文章的讽刺意味。但至少我坦诚地承认,这些内容是用你的保险费买的。
结论
React 并不差。它解决了实际问题,并引入了一些真正有用的模式。但在某个阶段,我们迷失了方向。我们开始将简单的 DOM 操作视为必须不惜一切代价避免的事情,这导致了越来越复杂的抽象,在解决虚构问题的同时,却制造了真正的问题。
下次你进行组件抽象时,问问自己:我真的让它变得更好了,还是我只是用花哨的蝴蝶结包装了“document.createElement()”?
0 Comments