type
status
date
slug
summary
tags
category
icon
password
Rendered more hooks than during the previous render
出现在需要兼容 Android 和 IOS 的时候,有一个组件的某个属性只希望在安卓上面有,而不希望在 IOS 上面有,就写成了这样:
问题:这里使用了条件性的 props 展开,在安卓和 iOS 平台上 RecyclerView 接收到的 props 不同,这可能导致:
- 组件内部状态不一致:RecyclerView 在安卓端有额外的 onRefresh 和 refreshing props
- 内部 hooks 调用差异:不同的 props 可能触发组件内部不同的 hooks 逻辑
仅在安卓上传递了 onRefresh 和 refreshing 这些 props,可能触发了内部的 useEffect、useState 等 hooks
修改:统一双端 props:
使用 useMemo 的时候,有一个变量在外部被计算但被用作依赖:
问题:
useMemo
的依赖数组[bottom]
引用了外部变量
- React 无法正确追踪这个依赖的变化
- 可能导致
useMemo
在某些渲染中被跳过或额外调用
修改:将计算逻辑移动到 useMemo 内部:
useCallback 和 useMemo 和 memo 什么时候用
useMemo
一般使用场景:
- 计算量比较大
- 计算量可能不大,但是要分成很多步才可以得到一个结果
useCallback
一般使用场景:
- 遇到性能问题,有函数需要传给子组件、并且子组件有用 React.memo 包裹的时候才有效果
- 该函数是某些 hook 的依赖项
一般原理:
- useCallback 会缓存函数本身
- useCallback 并不会阻止函数的创建,render时总会创建一个函数,但 React 会忽略它,并在没有任何依赖项改变的情况下返回一个缓存的函数
- 如果一个函数作为 prop 传递给子组件,每次父组件重新渲染时,子组件会认为这个函数发生了变化,从而触发子组件的重新渲染。
useCallback
可以确保传递给子组件的函数实例在依赖项不变的情况下不会改变,从而避免不必要的渲染。
memo
是 react 的高阶组件,高阶组件就是参数为组件,返回值为新组件的组件。
这个例子中,只有当 data 发生改变时,Child 组件才会重新被渲染。
小结论
- 计算量特别大的时候,像文档所说,创建或遍历数千个对象,要使用
useMemo
。其它情况用不用看个人习惯。
- 子组件重新渲染造成的影响很大的时候,子组件包裹
memo
,并且传递给子组件的函数用useCallback
包裹。否则使用useCallback
几乎没有作用。
- 开发了一个类似
react-use
、ahooks
的 npm 包,返回的函数方法要包裹useCallback
,使用的人可能需要做优化。
FlatList / ScrollView
ScrollView:
- 一次性渲染全部子元素的滚动容器
- 元素过多时会卡顿
- 官方文档建议:长列表不要用 ScrollView,要用 FlatList 或 SectionList
FlatList:
- 基于 ScrollView 封装的虚拟化长列表组件
- 只渲染屏幕区域 + 前后一定缓冲区的内容
- 滚动时卸载不可见元素并复用它们的组件实例
- 适合长列表、大数据量的场景,比如聊天、商品列表、Feed流
- 默认会控制渲染批次、窗口大小等(
initialNumToRender
,maxToRenderPerBatch
,windowSize
等属性)
ScrollView 使用场景:
- 列表数量少且固定
- 表单页面、图文详情页、设置页面
- 实现简单、可控性高,不需要配置虚拟化参数
- 列表和非列表内容混排
- 如果用
FlatList
,需要用ListHeaderComponent
、ListFooterComponent
来拼凑,反而结构更复杂
- 需要一次性获取列表全部高度
- 有些动画、滚动联动效果(比如滚动到一定位置吸顶)需要立即知道全部高度
- 嵌套滚动 / 横向滚动
- 例如外层是纵向
ScrollView
,内部是横向的图片ScrollView
- 多个虚拟化列表同时存在时,React Native 需要同时维护多个渲染窗口、多个回收机制
- 滚动事件多层传递会增加 JS 线程和原生 UI 线程的通信开销,可能导致掉帧
- Author:orangec
- URL:orange’s blog | welcome to my blog (clovy.top)/article/240c107a-b41d-8054-9a47-f1316dcb100d
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!