React 内置Hook 之 useMemo 的使用技巧、性能优化和实现原理

前言

React 16.8版本引入了许多内置的Hook,其中之一就是 useMemouseMemo 是一种记忆化(memoization)技术,它可以增加性能,帮助我们避免在每次渲染时都进行复杂的计算。

在本篇教程中,我将用易于理解的方式,通过实例和对比,进行深入分析 useMemo 的概念与应用。

什么是 useMemo

useMemo是一个React hook,用于返回一个记忆化的值。这个hook只在其相关依赖发生变化时才重新执行创建函数进行计算。如果依赖的值没有变化,useMemo将返回以前存储的记忆值。

javascript
const memoizedValue = useMemo(()=>{ // 在这里执行复杂缓慢的计算 return complexComputation(input); }, [input]); // 依赖于input的更改

使用案例

下面让我们通过一个具体的例子来深入理解 useMemo

设想我们正在构建一个电子音乐播放器。对于每首歌曲,我们需要将其长度(秒数)转化为 "分:秒" 的格式。例如,90秒要显示为 “1:30”。

以下是未使用 useMemo 的版本:

javascript
function MusicPlayer({ songDuration }) { const durationInMinSec = `${Math.floor(songDuration / 60)}:${songDuration % 60 < 10 ? '0' : ''}${songDuration % 60}`; return ( <div> <p>Song Duration: {durationInMinSec}</p> </div> ); }

此时,每当 songDuration 发生改变,转换操作都会重新进行,导致不必要的消耗。为了优化,我们可以使用 useMemo 来避免重复计算:

javascript
function MusicPlayer({ songDuration }) { const durationInMinSec = useMemo(() => { return `${Math.floor(songDuration / 60)}:${songDuration % 60 < 10 ? '0' : ''}${songDuration % 60}`; }, [songDuration]); return ( <div> <p>Song Duration: {durationInMinSec}</p> </div> ); }

现在 useMemo 会记住上一次的**songDuration**计算结果,只有当 songDuration 值真正发生变化时才会重新执行函数并返回新的结果。

useMemouseCallback的区别

相对于 useCallbackuseMemo更专注于优化复杂的计算或者保持对象和数组的引用不变。

useCallback(fn, deps) 等同于 useMemo(() => fn, deps)。也就是说 useCallback 是记忆化函数(reference equality),而 useMemo 是记忆化计算值。

useMomo的实现原理

在React Hooks内部,useMemo会为每一个Hook维护一个链表,存储每次计算的结果,然后根据输入的依赖数组,去进行Hash匹配,如果当前计算的依赖数组在链表中找到对应的匹配项,那么就返回相关的值,这样就避免了不必要的计算和渲染,提高了效率。

总结

希望这本教程能帮助你了解React的 useMemo,如何正确地使用它,以及在你的应用中为何使用它。记住,使用 useMemo 是有成本的(记忆化存储值需要空间),所以请根据实际需要,明智地利用它,避免对整个应用性能的影响。