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 或事件库,确实不好用(废话文学)。

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄1 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95271 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大1 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师1 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端