image.png

这一方法在短时间内显著提升了我应用的性能,我迫不及待地想与大家分享这些见解,而不是让它们被遗忘或被重复发现。

释放最佳用户体验

开发 React Native 应用通常从基本的业务逻辑开始,这是应用的核心。但随着开发的进展,用户体验(UX)迅速成为关注的焦点。用户期望流畅的交互、快速的响应和迅速的内容加载。在这种情况下,性能优化变得至关重要,这正是 React Hooks 发挥魔力的地方,使您的应用响应速度达到顶峰。

本文揭示了 React Hooks 的强大功能,这些功能是在 React 16.8 中引入的,可以提升您的 React Native 应用的性能。通过一个实际示例——轮播组件,我们将具体了解每个 Hook 的细节,并揭示它们提升应用效率的潜力。

鉴于本文的篇幅和深度,我提供了一个 TLDR 总结,以捕捉要点并便于快速理解。

TLDR:要点总结及实际场景

重点在 React.memo:通过使用 React.memo 包装组件(如 CarouselB),可以提高应用性能,避免不必要的重新渲染。例如,在主页的多图轮播中实现 React.memo,可以显著减少加载时间,提升用户体验,避免在导航过程中重复加载图片。
在实际场景中应用这些策略:如优化具有多个轮播图的主页,或管理带有交互元素的列表,可以显著改善 React 应用的性能和用户满意度。
用性能优化的 Hooks 赋能 React Native
React Hooks 提供了一种简化的方法来管理函数组件中的状态和副作用。以下是一些在性能提升方面尤为突出的关键 Hook:

  • useState:在函数范式中管理状态更新,减少不必要的重新渲染,从而提升性能。
  • useEffect:管理副作用,例如数据获取和定时器。将数据获取逻辑策略性地放在 useEffect 中,可以优化重新渲染,确保只有在实际数据变化时才发生重新渲染。
  • useMemo:帮助记住复杂计算的结果。通过存储复杂函数的结果,仅在依赖项变化时重新计算,useMemo 显著减少了不必要的处理。
  • useCallback:类似于 useMemo,这个 Hook 记住函数,特别适用于传递给子组件的 props。它避免了每次渲染时冗余的函数生成,从而提高了效率。

通过应用这些 Hooks,您可以显著提升 React Native 应用的性能,确保用户享受流畅、快速的体验。

React.memo:提升组件效率

React.memo 是在 React 16.6 中引入的一个高阶组件,作为记忆功能组件的工具。通过在属性保持不变时防止无谓的重新渲染,React.memo 显著减少了重新创建和重新渲染组件的工作量,这对 React Native 的性能是一大利好。

如何操作

  • 封装一个功能组件
  • 在后续渲染中,对新的和先前的属性进行浅层比较
  • 如果属性保持不变,则绕过重新渲染,而是重复使用最后渲染的输出
  • 如果检测到更改,将使用更新的属性重新渲染组件

注意:React.memo 默认进行浅层属性比较,可能会忽视对象或数组内部的深层变化。对于复杂的属性结构,可能需要实现自定义比较函数。

案例研究:通过钩子优化轮播组件

考虑 CarouselB 组件 - 一个循环显示图片的功能。提升其性能涉及到识别和纠正常见的问题:

挑战:

  • 不必要的重复渲染:频繁的,无理由的重复渲染可能会降低用户体验,导致视觉卡顿。
  • 低效的数据获取:获取轮播数据的延迟可能会延迟内容交付,考验用户的耐心。

诊断

问题可能源于次优的 useEffect 实现,或者由于状态管理不足或忽视了 React.memo 对于功能组件的使用,导致过度的重新渲染。

解决方案:

  • 高效的数据获取:使用 useEffect 钩子进行数据检索,将获取的数据作为依赖项,以确保重新渲染与实际数据更新保持一致。
  • 条件渲染:引入条件渲染以标示加载阶段,防止组件过早渲染并增强用户参与度。
  • 使用 React.memo 进行简化:将 CarouselB 封装在 React.memo 中可以最小化重新渲染,保持性能的同时只需要最小的代码调整。

概念到此为止….

然而,我想更详细地分享我的情况。

之前:

// The initial implementation of CarouselB
function CarouselB({
   snaptoitem,
   metadata,
   template = "default",
   titlebgcolor = "black",
   ...
   ...
   ...
}) 
{
...
...
...
}
export default withCarouselContext(CarouselB);

之后:

// Implement React.memo by simply wrapping CarouselB with MemoizedCarouselB
const MemoizedCarouselB = React.memo(CarouselB, (prevProps, currentProps) => {
  // Comparison logic
  return (
    prevProps.query === currentProps.query &&
    prevProps.url === currentProps.url &&
    prevProps.data === currentProps.data 
  );
});

function CarouselB({
   snaptoitem,
   metadata,
   template = "default",
   titlebgcolor = "black",
   ...
   ...
   ...
})
{
...
...
...
}

export default withCarouselContext(MemoizedCarouselB);

深入探索:CarouselB 组件独特的旅程

在我们追求完美用户体验的过程中,我们推出了 CarouselB——对传统旋转木马的定制版本。我们的主屏幕被设想为一个动态展示,不仅有一个,而是有五个 CarouselB 实例,每个都充满了 15 张生动的图片。这种设计选择并非随意的;它源于将主屏幕转变为全面的导航中心的愿景。通过 upfront 展示丰富的选项,我们的目标是最小化用户导航步骤,允许用户快速、直接地访问所需内容。

挑战:导航流畅性 vs. 性能

然而,雄心壮志往往伴随着一系列难题。一个显著的挑战来自于设计用来增强用户导航的特性:CarouselB 组件。用户在屏幕之间切换时遇到了一个明显的问题 - 每次返回主屏幕都会触发轮播图的重新加载,导致了冗余的数据获取。这不仅打断了用户体验的流畅性,也对应用程序的性能和效率产生了负面影响。

根本问题在于导航转换之间缺乏状态保留。每次重新访问屏幕都被视为新的开始,重新初始化我们的轮播图,从而重新下载相同的图片。这种冗余不仅仅是带宽的问题;它在用户体验中造成了明显的瑕疵,表现为重复的加载屏幕和不必要的延迟。

探索:从缓存到记忆化

为了解决这个问题,我们深入研究了可能的解决方案。最初,图像缓存似乎是一个有前途的途径——通过存储先前加载的图像,我们理论上可以大大减少加载时间。然而,实验表明,虽然缓存有其优点,但它并不能完全符合我们特定用例的要求或解冔核心问题:组件重新初始化

在寻求更全面的解决方案时,我们转向了 React 的优化武器库——引入了 React.memo。通过用 React.memo 包装我们的 CarouselB 组件,我们的目标是从根本上解决问题。假设很直接:如果我们能防止 CarouselB 组件的不必要的重新渲染,除非它们的属性发生变化,我们就可以从本质上保留它们的状态和内容,跨屏幕转换。

启示:React.memo 来解救

结果是变革性的。实施 React.memo 成为了我们优化工作中的关键。这一改变显著提升了主页的性能和用户体验。当用户从其他页面返回时,他们会看到一个即时响应的界面,所有的轮播组件完好无损,图片生动地显示,就像之前离开时一样。

这种在导航流畅性和内容稳定性方面的显著提升,是通过最小的代码修改实现的 —— 这证明了 React 的记忆化的强大力量。此外,这种方法与我们的总体设计理念完美契合:通过减少不必要的操作和提高应用程序的响应性来优化用户体验。

首发于公众号 大迁世界,欢迎关注。📝 每周一篇实用的前端文章 🛠️ 分享值得关注的开发工具 ❓ 有疑问?我来回答

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。


王大冶
68k 声望104.9k 粉丝