React 中, 为什么要用 Context? 直接使用全局变量不是更方便吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ethusdt
0.01D
V2EX    React

React 中, 为什么要用 Context? 直接使用全局变量不是更方便吗?

  •  1
     
  •   ethusdt
    FaiChou 2022-05-07 14:19:05 +08:00 4246 次点击
    这是一个创建于 1254 天前的主题,其中的信息可能已经有所发展或是发生改变。

    未免有点标题党, 且先看我写的这个 demo:

    import React from 'react'; let obj = null; let listener = null; function getObj() { return obj; } function setListener(l) { listener = l; } function setObj(o) { obj = o; if (listener) { listener(o); } } function useObj() { const [, forceUpdate] = React.useReducer(x=>x+1,0); React.useEffect(() => { setListener(() => forceUpdate()) }, []) return getObj(); } function Component1() { return ( <div> <button OnClick={() => {setObj(Math.random())}}>setrandom</button> </div> ) } function Component2() { const o = useObj(); return ( <div> {o} </div> ) } export default function App() { return ( <div> <Component1 /> <Component2 /> </div> ); } 

    先说下 Context 一个缺点, 当数据改变时, 在 Context.Provider 下的节点都会重新执行, 这样很多不用其数据的节点也会被打扰, 昨天的帖子讨论过: 用 Context+Hooks 替代 Redux. 认真看了下大家的评论, 要么是用 memo 来固定住不想被打扰的组件, 要么使用一个订阅模式来刷新并通知.

    与其这么麻烦, 不如直接用上面代码中的方法. 毕竟 Context 可以看作是一个全局的数据, 任意节点想使用这个数据时候, 还是需要 import 这个 Context.

    上面代码和 redux 很像, 有一个 listener, 但 redux 需要靠 connect 绑定组件来订阅刷新, connect 利用了 Context.Provider+订阅+useSyncExternalStore 这个 API 来实现的.

    还不如直接简简单单使用上面这种方式, 当节点使用全局数据时候, 使用自定义 hook 插一个 listener 进去, 当数据变动, 进行 forceUpdate. 这样也会避免了牵一发动全身的全部刷新, 只有使用 useObj() 的组件才会被刷新.

    ps. 我写的项目少, 只是看文档时候产生的一点想法. 求大佬指正

    12 条回复    2022-05-08 22:42:42 +08:00
    codefever
        1
    codefever  
       2022-05-07 14:24:46 +08:00
    没有 Context 的时候父组件向子组件传递 props 属性只能在组件树上自上而下进行传递,但是有些属性并不是组件树的每层节点都有相同的需求,这样我们再逐层传递 props 就显得代码很繁琐笨重。
    noe132
        2
    noe132  
       2022-05-07 14:31:13 +08:00 via Android
    假设你写了个第三方库,一些组件依赖一些父组件的状态,但它们不是直接父子关系,而且可能被用户随意组合,这时候 context 就是非常好的工具
    XCFOX
        3
    XCFOX  
       2022-05-07 15:08:00 +08:00
    你说的很对,用全局变量再加上 render-optimized 是个不错的方案,valtio 就是这么干的
    https://github.com/pmndrs/valtio
    XCFOX
        4
    XCFOX  
       2022-05-07 15:15:39 +08:00
    转念一想,其实大家早就看不惯 React 这种函数式的贪婪更新机制。
    所以后来的 Vue3 、Svelte 、Solid 都是监听变化按需更新,可以说它们比 React 更 reactive ,性能比 React 好不少,也没有到处 useMemo 、memo 的烦恼。
    vue3 是我觉得最舒服的,reactive 对象可以作为全局变量存在于组件之外,这样极大方便了组件间通信。不过话说回来,全局变量还是得小心地用,不然会有内存驻留的风险。
    yyfearth
        5
    yyfearth  
       2022-05-07 15:50:31 +08:00
    @FaiChou 用 Context 而不是 Global
    如果你是写可复用组件 而不是你例子里面这种单例组件 你就完全没办法用 global

    用 Context 本来就是要避免平凡的更新里面的东西 如果只需要取值 不需要刷新 可以用 Context 传递 Ref

    我写全局单例组件的时候 一般也用 Global 的多 但是可复用组件 就不能用 Global 了
    yyfearth
        6
    yyfearth  
       2022-05-07 15:53:00 +08:00
    @XCFOX React 的 virtual dom 就是那个时代的产物
    那个时代没有现在这么强大的工具链可以做到 Svelte 那样
    要兼容浏览器也没有 Proxy 来做到原生 reactive

    有了强大的编译器和现代浏览器 确实完全不需要 virtual dom 了
    rioshikelong121
        7
    rioshikelong121  
       2022-05-07 15:55:22 +08:00
    redux 也支持 hook API (useDispatch, useSelector) 啊,也不需要显式使用 connect ,我觉得这就够了。
    比你个方案好的是支持 middleware 这样的机制。
    ethusdt
        8
    ethusdt  
    OP
       2022-05-07 15:59:25 +08:00
    @rioshikelong121 的确, 代替的是 react-redux 而没有代替 redux, 因为 redux 支持中间件.
    gouflv
        9
    gouflv  
       2022-05-07 17:03:17 +08:00 via iPhone
    context 是可以分层级管理的,作用域更小,同时还具有生命周期
    bojue
        10
    bojue  
       2022-05-07 23:50:05 +08:00
    @codefever Content 能避免逐层传递呀
    chenliangngng
        11
    chenliangngng  
       2022-05-08 12:30:54 +08:00
    登录状态我这里就是全局变量+闭包控制的,没有用 redux 也没有用 hooks 也没有用 context 。原因很简单,我希望这个状态和 react 生态解耦。一些其他需要用到登录状态的中间件,我没必要用 react 的方式去写

    看你业务场景吧,适合就是好的。微前端场景,完全可以全局变量+闭包;全局状态的场景,可以用 redux 也可以用 context ,而且尽量减少全局状态,尽量减少状态,少用状态管理,因为这会让项目指数级复杂化;一个模块的状态,用 context 是最好的,在模块最顶级文件使用,可以保证其他模块不去用,不需要 props 传参
    shiye515
        12
    shiye515  
       2022-05-08 22:42:42 +08:00
    自己一个人开发的时候随便,很多人一起合作的时候根本找不到全局变量是被谁在什么时候改了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3404 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 00:40 PVG 08:40 LAX 17:40 JFK 20:40
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86