V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
React
sillydaddy
V2EX  ›  React

一个组件比较多的页面,即使更新一个小组件,也必须走一遍整个页面的 render ,怎么处理呢?

  •  
  •   sillydaddy · 123 天前 · 1846 次点击
    这是一个创建于 123 天前的主题,其中的信息可能已经有所发展或是发生改变。
    现在有一个 react 构造的页面,页面上有很多元素。整个页面是根据一个数据文档(data_document),自顶向下构造的构造的。
    自顶向下就是说,使用 data_document.dataA 构造组件 A,data_document.dataB 构造组件 B 。。然后使用 dataA 里面的子 dataAA,构造组件 A 里的子组件 AA 。

    这里有个问题是,当我操作了页面里面很小的一个组件,从而修改了这个组件对应的 data 时,我需要触发页面的根组件 render(),将整个页面构造一遍。我的思考是,这些页面里的所有组件,都是由 data_document 里的某些 data 完全决定的,它们显示状态变了,就意味着 data_document 变了,反过来也是。所有的组件都是没有额外的状态 state 的。所以想要操作某个组件改变它的状态,就要改变 data_document 的某些 data,将新 data 作为 props 再传递给它。由于整个页面的构建是自顶向下构造的,想要改变传递给某个子组件的 props,就需要跑页面根组件的 render()。

    虽然 render 只是重新构造整个虚拟 dom 树而不是真实 dom 树,但如果组件多的话,跑一遍也很费时间。对于这种情况,有什么好的思路吗?
    ( 这里要注意的是,由于多个组件可能会用同一个数据,所以每次的修改都要即时反馈到 data_document 中,这样的话让被修改的组件只更新自己的 state 就行不通了。)
    第 1 条附言  ·  122 天前
    了解了一遍大家提到的
    Context/memo/PureComponent/ShouldComponentUpdate/immer/Redux/mobx/...
    概念好多哎。。

    综合了解之后,发现大家的回复,是在解决 2 个问题,
    1 是 props drilling——某个子组件的属性,需要由祖宗组件一直传递下去
    2 是没有数据更新时,也要无效地 re-render

    第 1 个问题,对于主题里提到的例子,不是问题。因为数据是分层的,父组件传给子组件的是子级数据,没有重复传递同一数据的嫌疑;假如确实有 props drilling 这个问题,用 Context 和 Redux 解决挺合适的。

    主题里存在的主要是第 2 个问题。我看了一下,发现 memo 挺适合解决的——只要 props 没改变,就可以用之前缓存的渲染结果。这个跟 PureComponent 是类似的(PureComponent 好像 props 和 state 都要判断)。当然,判断 props 是否发生了改变,需要配合 immutable(不可变数据)使用,immutable 让判断数据内容是否发生了改变只需要作 shallow compare(引用比较)即可,哪怕是数据对象里嵌套的深层属性发生了变化。如果用 immutable(不可变数据)的话,自己手写 ShouldComponentUpdate 也不麻烦,PureComponent 连这点麻烦也省去了。

    谢谢大家的回复。现在对 React 这块的性能优化有点底了。
    24 条回复    2021-08-05 20:47:47 +08:00
    shakukansp
        1
    shakukansp  
       122 天前
    办法就是不用 react……
    kop1989
        2
    kop1989  
       122 天前
    所以你要去学习 react Context 的使用。
    binaryify
        3
    binaryify  
       122 天前   ❤️ 1
    人生苦短,我用 Vue
    kop1989
        4
    kop1989  
       122 天前
    换而言之,如果一个 dom 的数据与逻辑必须强依赖其“父亲”,那其实他就不是一个独立的“组件”,其渲染与数据处理的动作必然和其他兄弟组件有耦合关系(前提是你的组件规划合理)。所以你也应该接受带者父亲整体重绘。
    kop1989
        5
    kop1989  
       122 天前
    而传统的针对性操作子 dom 组件的方式,其实是你通过人脑处理了兄弟组件的耦合关系。
    而 react 等工程化库的目的,就是将组件间充分解耦。

    解耦的结果必然会出现冗余与浪费。而当前的互联网带宽与客户端性能也禁得起这样的浪费。
    sillydaddy
        6
    sillydaddy  
    OP
       122 天前
    @kop1989
    不太明白。组件的一个作用是可以复用。这里我看不出父组件与子组件有什么“强依赖”的关系。父组件只是把数据传递给子组件啊。比如父组件 A 下面有子组件 A1 、A2 、A3,子组件 A1 变了,修改 A1 对应的数据 data1,这时 A2,A3 数据根本没有变化,也没有依赖 A1,但是也要重绘。
    kop1989
        7
    kop1989  
       122 天前
    @sillydaddy #6 所以你的解决方式有两种。

    1 、将 A1 剥离 A 。
    2 、通过全局变量(比如 context )来控制 A1 所需要的数据。

    如果这两者都不能,那就其实说明 A1 与 A,以及 A2A3 其实有耦合关系。只不过未见得是数据上的。
    huai
        8
    huai  
       122 天前   ❤️ 1
    @sillydaddy 大多时候不会存在啥性能问题,需要的时候 可以看看

    React.memo

    PureComponent

    shouldcomponentupdate
    binaryify
        9
    binaryify  
       122 天前   ❤️ 1
    用 shouldcomponentupdate 比较数据或者 mobx 自动判断
    XTTX
        10
    XTTX  
       122 天前
    现在都在用 useEffect 替代 cmd,purecomponet 。useCallback 对应 function useMemo 对应运算结果。 建议 op 去学 react hooks, 因为它已经是主流了
    dashixiong1990
        11
    dashixiong1990  
       122 天前   ❤️ 1
    组件 React.memo
    数据 immer
    XTTX
        12
    XTTX  
       122 天前
    react hooks 里 包括 useContext, 可以带入 reducer. 你描述的问题就是 react 以前的传统问题,hooks 可以解决。useContext 大部分情况下替代 redux 。你设计好的话,prop drilling 不会是问题。
    DICK23
        13
    DICK23  
       122 天前
    render 消耗其实不太大,大部分组件哪怕重新走了一遍 render 流程,实际性能影响微乎其微。
    实在不行就手写 memo 的比较函数,手动指定依赖值
    sherryqueen
        14
    sherryqueen  
       122 天前
    memo 比较函数.
    sweetcola
        15
    sweetcola  
       122 天前
    可以把数据拆分成几个 reducer(slice) 放进 Redux 里,把 state 下沉到子组件。
    ykrank
        16
    ykrank  
       122 天前
    你需要的是 mobx 之类吧
    chenpingan
        17
    chenpingan  
       122 天前
    react.memo 或者 useMemo 都可以解决这个问题
    KouShuiYu
        18
    KouShuiYu  
       122 天前
    改用 vue 就不会有这个问题,
    charlie21
        19
    charlie21  
       122 天前
    很典型的问题
    meteor957
        21
    meteor957  
       122 天前
    引用类型用 useMemo 包裹,配合 React.memo

    用 react 肯定避免不了 re-render,但是渲染耗时大的组件,应该要做性能优化去减少重复渲染。

    普通的组件像 button 那种,不需太关心。
    66beta
        22
    66beta  
       122 天前
    所以为什么小尤同志敢说 vue 性能略高于 react~
    xutao881
        23
    xutao881  
       122 天前
    在你的业务场景还没有触及到 react 性能瓶颈的时候,没必要去担心 render 的性能问题,写 class 组件确实有这种层层传递 prop 的问题,更多的时候你应该考虑怎么去提取复杂 prop 到全局管理,如果还是觉得不爽,用 hooks 吧,监听父级变动可以很优雅。
    aaronlam
        24
    aaronlam  
       122 天前 via iPhone
    楼主自己根据大伙的答案总结还是很到位,很赞!
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4132 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:27 · PVG 10:27 · LAX 18:27 · JFK 21:27
    ♥ Do have faith in what you're doing.