Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

精读《用 React 做按需渲染》 #254

Closed
ascoders opened this issue Jun 6, 2020 · 15 comments
Closed

精读《用 React 做按需渲染》 #254

ascoders opened this issue Jun 6, 2020 · 15 comments

Comments

@ascoders
Copy link
Owner

ascoders commented Jun 6, 2020

本周说一些干货,精读来源于笔者项目经验。

按需渲染是前端性能优化重要手段,尤其当页面元素过多时,不在可视区域的元素可以禁止重渲染以提升性能,那么怎么做呢?本期精读就分享一下笔者的方法。


精读《用 React 做按需渲染》

@ascoders ascoders closed this as completed Jun 8, 2020
@ositowang
Copy link

shouldComponentUpdate() 此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug. 这里可能会产生什么样的bug呢?

@ascoders
Copy link
Owner Author

@ositowang bug 指的是该渲染时不渲染。

官方的意思我换个角度翻译一下:

  1. 正常情况用 PureComponent 即可,这样仅 props 引用变化才导致渲染。
  2. 有其他特殊阻止渲染的需求再用 shouldComponentUpdate,不要用 shouldComponentUpdate 模拟 PureComponent,没意义且容易写错。

为什么会出 bug 呢?当然 是 shouldComponentUpdate 可能写的有问题,可能用的是白名单,导致该渲染时不渲染。

@Rainsho
Copy link

Rainsho commented Jun 19, 2020

class RenderWhenActive extends React.Component {
  public shouldComponentUpdate(nextProps) {
    return nextProps.active;
  }

  public render() {
    return this.props.children
  }
}

有点疑惑,不用 HOC 的话 props.children 自身的状态改变了,还是会触发 children 重新渲染啊。

@ascoders
Copy link
Owner Author

@Rainsho 只阻塞外层导致的重渲染,组件自己的不会。

@MwumLi
Copy link

MwumLi commented Jul 7, 2020

这段代码没看懂, 怎么回事长度之和 + 两倍间距

// 长度之和 + 两倍间距(交叉则间距为负)
    const sumOfWidthWithGap = Math.abs(
      rootComponentRect.left + rootComponentRect.right - componentRect.left - componentRect.right,
    );
    // 宽度之和 + 两倍间距(交叉则间距为负)
    const sumOfHeightWithGap = Math.abs(
      rootComponentRect.bottom + rootComponentRect.top - componentRect.bottom - componentRect.top,
    );

@ascoders
Copy link
Owner Author

ascoders commented Jul 7, 2020

可以画个图感受一下,这里间距指的是左矩形右侧边,与右矩形左侧边的距离,可以为负。

@zhouping3
Copy link

如果只考虑首次渲染且组件数很多的情况,因为是自由布局不好用虚拟渲染技术,虽然使用这种方式不能够避免首次渲染dom树大体结构,但是可以减少每个dom结构内其他元素的渲染时间。

@zhouping3
Copy link

感觉这种方式首次渲染还是硬伤,假如来个几千个节点首次还是有点慢

@ascoders
Copy link
Owner Author

几千个组件确实会慢,但这种搭建场景很少,更多的是某个组件数据量很大,只要不在画布区域组件停止重渲染就好了。

@dengnan123
Copy link

几千个组件确实会慢,但这种搭建场景很少,更多的是某个组件数据量很大,只要不在画布区域组件停止重渲染就好了。

那不就是按需渲染吗

@dengnan123
Copy link

几千个组件确实会慢,但这种搭建场景很少,更多的是某个组件数据量很大,只要不在画布区域组件停止重渲染就好了。

或者第一次不在可视范围,就不加载对应的组件js,按需加载岂不是渲染的更快

@ascoders
Copy link
Owner Author

ascoders commented Jun 1, 2021

理论上可行,但其实和布局方式有关,要做到首次就按需,得提前计算布局是否在可视区域内,而这样在某些弹性布局时可能算不准,所以渲染后再判断位置是最可靠的。

@ckhesy
Copy link

ckhesy commented Nov 7, 2021

目前 Function Component 做不到这一点,我们仍需借助 Class Component 的 shouldComponentUpdate 做到这一点,因为 Class Component 阻塞渲染时,会将最新 props 存储下来,而 Function Component 完全没有内部状态,目前还无法胜任这项工作。

======================================

react.memo不也可以解决么

const RenderWhenActive = React.memo((props:any) => {
return <>{props.children}</>
}, (prevProps, nextProps) => {
return !nextProps.active;
})

@ascoders
Copy link
Owner Author

ascoders commented Nov 7, 2021

@ckhesy sorry,是我的错误,当时写的时候没考虑到这个 API。现在已经更新啦!

@liyanging
Copy link

为何不能直接用 componentRect.top - rootComponentRect.bottom 呢?小于0,代表在纵向有相交呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants