react 组件重新渲染的问题

2023-03-02 09:25:47 +08:00
 oppddd
有一个页面, 包含 table table 有操作选项,点击后会弹窗进行操作,关闭弹窗刷新 table

一个很普通的页面

问题:

1. 如何组织弹窗的 showState ?

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

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

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

有什么最佳实践吗?
3108 次点击
所在节点    React
24 条回复
chairuosen
2023-03-02 09:35:00 +08:00
应该是 2 ,担心性能的话,把 table 再封一个?
leoskey
2023-03-02 09:42:25 +08:00
可以参考这篇文章《 React 组件性能优化:如何避免不必要的 re-render 》 https://mp.weixin.qq.com/s/z9GaB_48LHtL-if4mP-nZQ
superedlimited
2023-03-02 09:48:02 +08:00
弹窗的 showState 放到 useMemo ,就不会导致 table 重新渲染了
AyaseEri
2023-03-02 09:56:58 +08:00
把弹窗封成一个独立组件,内部维护 showState ,对外暴露一个 toggle 接口,通过 ref 的形式让外部控制自己的显隐
或者是像 antd 那几个提示一样直接写成一个 function ,每次直接 call function 弹开弹窗
ChefIsAwesome
2023-03-02 10:26:08 +08:00
table 一个组件,dialog 一个组件。上面再套一层组件,相当于中间人沟通二者。
多个 dialog 也行。你想象一下 select ,实际也是弹窗。每行来一个,没人觉得奇怪。只要 dialog 关闭的时候,把 Dom 清空就行。
suzic
2023-03-02 10:32:37 +08:00
2 。会导致重新渲染么?不太懂 react ,在 vue 里边如果状态和表格无关的话,那部分是不会重新渲染的
oppddd
2023-03-02 10:37:49 +08:00
@suzic 会的,因为 vue 是将状态和副作用 render 进行了细粒度的绑定,react 不是,只要 setstate ,父组件子组件都跟着 rerender
oppddd
2023-03-02 10:41:54 +08:00
@ChefIsAwesome 再套一个组件也会 rerender ,比如我点击一个按钮,要显示用户详情,那么弹窗就需要知道是什么 userId ,那就会导致状态提升,那么三个组件都会 rerender ;
oppddd
2023-03-02 10:42:44 +08:00
@AyaseEri 嗯,感觉通过 ref 能减少 rerender ,还能减少 dialog 组件实例
joesonw
2023-03-02 10:53:46 +08:00
table 依赖的状态变化了才会刷新,例如有个按钮的 onClick 你直接原地手写的,每次都会变的,要用 useCallback 包起来。类似的检查检查,不会无故刷新的。
suzic
2023-03-02 10:55:27 +08:00
@liuxsen93 我猜可以通过包装一个方法,每次调用时手动插入弹窗 dom ,每次用完自动销毁? vue 可以这样玩的,react 应该也可以,原理一样
ChefIsAwesome
2023-03-02 10:57:47 +08:00
@liuxsen93 你再琢磨琢磨。ID 存父组件上,传给 dialog ,table 只是改这个 ID ,不用收这个 ID 。
donlian
2023-03-02 10:58:19 +08:00
子组件用 React.memo 包一下,这样就不会 props 没变就触发 rerender 了
sjhhjx0122
2023-03-02 11:23:10 +08:00
推荐一下我一直在用的维护弹窗的 hook https://github.com/eBay/nice-modal-react 通过这个插件你就可以只创建一个弹窗实例,并且不维护 showState ,切用命令式调用
dsa999
2023-03-02 11:31:18 +08:00
我觉得弹出层最好放在外层,比如通过 portal 放到 body 下,这样就不会有样式污染的问题。
不过我目前的做法是使用 ReactDom 中的 createRoot 方法,在 body 下创建一个新的根节点处理弹出层。
优点:
1. 不会出现你说的重新渲染问题。
2. 不需要 showState ,通过 render/destroy 控制显隐即可。
缺点:
1. 由于是独立的两个根节点,会造成无法共享 context 等问题,不过可以通过 render 时把数据作为参数传入。
yuuko
2023-03-02 11:42:33 +08:00
把弹窗放在 cell 组建,显示的时候挂载弹窗,不显示销毁,就不会存在多个实例了
Ritr
2023-03-02 12:46:17 +08:00
当然是子路由啦,把弹框放到子路由里面就可以了
monologue520
2023-03-02 13:55:46 +08:00
2 , 有时候是需要 table 重复渲染的,比如说 dialog 中操作改变了 table
sunwang
2023-03-02 14:01:40 +08:00
这种情况还是倾向于在父级维护 showState ,像新增按钮这种倒是可以和弹窗封装到在一起
sjhhjx0122
2023-03-02 14:34:43 +08:00
@dsa999 其实有办法拿到上下文的,可以创建一个 ModalProvider 组件专门维护所有弹窗状态和渲染,用 context 传递状态和组件,然后拿这个组件包裹在根组件上,写一个 hook 传递 modal 给 ModalProvide 渲染,如果需要当前组件的上下文就把 ModalProvider 包在当前组件上,就能拿到上下文

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/920362

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX