React 批判 2 则

React 哲学号称一套一套的,我也总结过一部分。React 的某些设计确实是挺巧妙的,但这只是 React 的其中一面。

某些情况下,这些说辞真的是一种对 React 的"自适应",换言之,找理由来掩饰 React 的设计缺陷。在某些场景下,这些设计缺陷会变得很难绕过,甚至绕不过,要不怎么说用 React 心智负担高呢。

事件的依赖

useEffect 依赖管理十分困难这件事众所周知,这个问题也算是其中一个特别难解决的分支。

举个例子,这里有一个非 React 原生库,想要包装成 React 组件。

viselect/packages/react/src/SelectionArea.tsx at master · simonwep/viselect

可以看到作者在封装的时候是没有把 useEffect 里所有使用的值都加入依赖,直接当初始化使用。当然一般情况下是没有问题的,但是如果你的传入的 props.onStart 里面引用了 useState 的变量呢?

那就完了。它不会生效的,因为该state更新时,这个 useEffect 根本不会更新,所以拿到的永远只有最开始的值。

例子,注意图中高亮区域:

如果把 props.onStart 加入了依赖又会怎么样呢?当然可以的,但是这又意味着整个初始化过程会重复运行,这简直毫无意义,纯纯的嫌用户电脑性能太高。

那到底怎么办?你可以把函数里面用到的会变化的值统统换成 ref,这样能用,不过非常难看,我们接着看。

其实有比较官方、也优雅一点的办法的:使用 useEffectEvent,至少它现在还叫这个名字,因为 React 到 19 发布为止,它都还是个实验性功能。

useEffectEvent 里面的函数不需要写依赖,依然能让所有使用的值是最新的。使用的场景就基本针对于上述的"事件触发"场景。

官网给出的示例代码:

tsx 复制代码
function ChatRoom({ roomId, theme }) {
  const onConnected = useEffectEvent(() => {
    showNotification('Connected!', theme);
  });

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.on('connected', () => {
      onConnected();
    });
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]); // ✅ All dependencies declared
  // ...

清理顺序

useEffect() parent-child cleanup order · Issue #16728 · facebook/react

useEffect 的清理看起来很优雅,所有相关代码都内聚在一个函数里。

然而,React 清理副作用时的顺序有点任性,有可能你在父组件清除函数已经把你要用的东西 destroy 了,子组件的清除函数还使用了被父组件 destroy 的对象,于是产生了很奇妙的错误,这又是一个对非 React 原生库接入非常不友好的一个点。

而且,这个问题 React 团队甚至是不打算解决的。一般情况,你可以冒着内存泄漏的风险不管它,如果你一定要解决的话,你就得自己写 workaround 来处理全局的 destroy 了。

所以

虽然 React 确实好用,但是在某些情况,例如你使用了非 React 原生的 UI 或事件库,确实不好用(废话文学)。

相关推荐
yinuo6 分钟前
CSS基础动画keyframes
前端
一条上岸小咸鱼1 小时前
Kotlin 基本数据类型(一):Numbers
android·前端·kotlin
前端小巷子1 小时前
Vue 事件绑定机制
前端·vue.js·面试
uhakadotcom1 小时前
开源:subdomainpy快速高效的 Python 子域名检测工具
前端·后端·面试
爱加班的猫1 小时前
Node.js 中 require 函数的原理深度解析
前端·node.js
用户8165111263971 小时前
WWDC 2025 Build a SwiftUI app with the new design
前端
小遁哥2 小时前
也是用上webworker了
react.js·性能优化
伍哥的传说2 小时前
Vue 3.5重磅更新:响应式Props解构,让组件开发更简洁高效
前端·javascript·vue.js·defineprops·vue 3.5·响应式props解构·vue.js新特性
阅文作家助手开发团队_山神2 小时前
第一章: Mac Flutter Engine开发准备工作
前端·flutter