react 组件重新渲染的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
oppddd
V2EX    React

react 组件重新渲染的问题

  •  
  •   oppddd 2023-03-02 09:25:47 +08:00 via iPhone 3606 次点击
    这是一个创建于 954 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有一个页面, 包含 table table 有操作选项,点击后会弹窗进行操作,关闭弹窗刷新 table

    一个很普通的页面

    问题:

    1. 如何组织弹窗的 showState ?

    在弹窗组件里面管理是否 show ,决定了应该把弹窗组件放在操作拦 每一个 cell 中,这样会生成多个弹窗实例,感觉不太好

    2. 弹窗应该放在什么位置?

    如果放在跟 table 同级,这样频繁的点击操作拦的查看按钮,会导致 table 重新渲染

    有什么最佳实践吗?
    24 条回复    2023-03-07 18:55:08 +08:00
    chairuosen
        1
    chairuosen  
       2023-03-02 09:35:00 +08:00
    应该是 2 ,担心性能的话,把 table 再封一个?
    leoskey
        2
    leoskey  
       2023-03-02 09:42:25 +08:00
    可以参考这篇文章《 React 组件性能优化:如何避免不必要的 re-render 》 https://mp.weixin.qq.com/s/z9GaB_48LHtL-if4mP-nZQ
    superedlimited
        3
    superedlimited  
       2023-03-02 09:48:02 +08:00
    弹窗的 showState 放到 useMemo ,就不会导致 table 重新渲染了
    AyaseEri
        4
    AyaseEri  
       2023-03-02 09:56:58 +08:00
    把弹窗封成一个独立组件,内部维护 showState ,对外暴露一个 toggle 接口,通过 ref 的形式让外部控制自己的显隐
    或者是像 antd 那几个提示一样直接写成一个 function ,每次直接 call function 弹开弹窗
    ChefIsAwesome
        5
    ChefIsAwesome  
       2023-03-02 10:26:08 +08:00 via Android
    table 一个组件,dialog 一个组件。上面再套一层组件,相当于中间人沟通二者。
    多个 dialog 也行。你想象一下 select ,实际也是弹窗。每行来一个,没人觉得奇怪。只要 dialog 关闭的时候,把 Dom 清空就行。
    suzic
        6
    suzic  
       2023-03-02 10:32:37 +08:00 via Android
    2 。会导致重新渲染么?不太懂 react ,在 vue 里边如果状态和表格无关的话,那部分是不会重新渲染的
    oppddd
        7
    oppddd  
    OP
       2023-03-02 10:37:49 +08:00
    @suzic 会的,因为 vue 是将状态和副作用 render 进行了细粒度的绑定,react 不是,只要 setstate ,父组件子组件都跟着 rerender
    oppddd
        8
    oppddd  
    OP
       2023-03-02 10:41:54 +08:00
    @ChefIsAwesome 再套一个组件也会 rerender ,比如我点击一个按钮,要显示用户详情,那么弹窗就需要知道是什么 userId ,那就会导致状态提升,那么三个组件都会 rerender ;
    oppddd
        9
    oppddd  
    OP
       2023-03-02 10:42:44 +08:00
    @AyaseEri 嗯,感觉通过 ref 能减少 rerender ,还能减少 dialog 组件实例
    joesonw
        10
    joesonw  
       2023-03-02 10:53:46 +08:00 via iPhone
    table 依赖的状态变化了才会刷新,例如有个按钮的 onClick 你直接原地手写的,每次都会变的,要用 useCallback 包起来。类似的检查检查,不会无故刷新的。
    suzic
        11
    suzic  
       2023-03-02 10:55:27 +08:00 via Android
    @liuxsen93 我猜可以通过包装一个方法,每次调用时手动插入弹窗 dom ,每次用完自动销毁? vue 可以这样玩的,react 应该也可以,原理一样
    ChefIsAwesome
        12
    ChefIsAwesome  
       2023-03-02 10:57:47 +08:00 via Android
    @liuxsen93 你再琢磨琢磨。ID 存父组件上,传给 dialog ,table 只是改这个 ID ,不用收这个 ID 。
    donlian
        13
    donlian  
       2023-03-02 10:58:19 +08:00 via iPhone
    子组件用 React.memo 包一下,这样就不会 props 没变就触发 rerender 了
    linkopeneyes
        14
    linkopeneyes  
       2023-03-02 11:23:10 +08:00   1
    推荐一下我一直在用的维护弹窗的 hook https://github.com/eBay/nice-modal-react 通过这个插件你就可以只创建一个弹窗实例,并且不维护 showState ,切用命令式调用
    dsa999
        15
    dsa999  
       2023-03-02 11:31:18 +08:00
    我觉得弹出层最好放在外层,比如通过 portal 放到 body 下,这样就不会有样式污染的问题。
    不过我目前的做法是使用 ReactDom 中的 createRoot 方法,在 body 下创建一个新的根节点处理弹出层。
    优点:
    1. 不会出现你说的重新渲染问题。
    2. 不需要 showState ,通过 render/destroy 控制显隐即可。
    缺点:
    1. 由于是独立的两个根节点,会造成无法共享 context 等问题,不过可以通过 render 时把数据作为参数传入。
    yuuko
        16
    yuuko  
       2023-03-02 11:42:33 +08:00
    把弹窗放在 cell 组建,显示的时候挂载弹窗,不显示销毁,就不会存在多个实例了
    Ritr
        17
    Ritr  
       2023-03-02 12:46:17 +08:00
    当然是子路由啦,把弹框放到子路由里面就可以了
    monologue520
        18
    monologue520  
       2023-03-02 13:55:46 +08:00
    2 , 有时候是需要 table 重复渲染的,比如说 dialog 中操作改变了 table
    sunwang
        19
    sunwang  
       2023-03-02 14:01:40 +08:00
    这种情况还是倾向于在父级维护 showState ,像新增按钮这种倒是可以和弹窗封装到在一起
    linkopeneyes
        20
    linkopeneyes  
       2023-03-02 14:34:43 +08:00
    @dsa999 其实有办法拿到上下文的,可以创建一个 ModalProvider 组件专门维护所有弹窗状态和渲染,用 context 传递状态和组件,然后拿这个组件包裹在根组件上,写一个 hook 传递 modal 给 ModalProvide 渲染,如果需要当前组件的上下文就把 ModalProvider 包在当前组件上,就能拿到上下文
    otakustay
        21
    otakustay  
       2023-03-02 16:05:13 +08:00
    把触发弹窗的 button 包个组件,里面管 show 状态,这样 table 就不会渲染了。至于多个弹窗实例,用{show && <Modal />}管呗,全局遮罩层一下,不就只有一个了么
    jjwjiang
        22
    jjwjiang  
       2023-03-02 16:16:45 +08:00
    在 react hooks 里不应该恐惧一般情况下产生的 re-render 。整个组件级别的 re-render 依然会被 react 优化成只对弹窗部分 re-render
    dsa999
        23
    dsa999  
       2023-03-02 18:19:56 +08:00
    @sjhhjx0122 嗯,不过大多数场景下 render 时传参也够用了。弹出层从交互上来看,本来就是处理额外的独立逻辑的嘛
    oppddd
        24
    oppddd  
    OP
       2023-03-07 18:55:08 +08:00
    @sjhhjx0122 看了这个仓库,用着很舒服!大佬啊
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2674 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 13:50 PVG 21:50 LAX 06:50 JFK 09:50
    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