react-use createMemo 源码解析:用 Hook 工厂把任意纯函数变成可缓存的 React Hook
react-use createMemo 源码解析用 Hook 工厂把任意纯函数变成可缓存的 React Hook【免费下载链接】react-useReact Hooks — 项目地址: https://gitcode.com/gh_mirrors/re/react-use导读createMemo是 react-use 提供的 Hook 工厂Hook factory它接收一个待记忆化memoize的函数返回一个记忆化的 React Hook。调用返回的 Hook 时传入与原函数相同的参数即可获得与原函数相同的结果并且结果会被 React 的useMemo缓存起来。本文以 docs/createMemo.md 为核心骨架结合 src/factory/createMemo.ts 的源码实现与 tests/createMemo.test.ts 的测试用例从使用方式、实现原理、缓存机制到适用边界做一次完整的讲解读完你可以把任意昂贵计算函数快速封装为可缓存的 Hook并理解它与直接使用useMemo的差异。一、createMemo是什么按照 react-use 官方文档的定义createMemo是一个Hook factoryHook factory, receives a function to be memoized, returns a memoized React hook, which receives the same arguments and returns the same result as the original function.它把「函数式编程中的记忆化memoization」迁移到了 React Hooks 的语境中。在整个 react-use 的状态类State工具集中createMemo与createReducer、createReducerContext、createGlobalState等同属工厂一族负责通过工厂函数批量生成语义化 Hook。在 README.md 中createMemo被归类为 factory of memoized hooks记忆化 Hook 的工厂。在 react-use 的 State 分类下工厂类工具还包括createReducer— 带自定义中间件的 reducer Hook 工厂createReducerContext/createStateContext— 组件间共享状态的 Hook 工厂createGlobalState— 跨组件共享状态createBreakpoint— 监听innerWidth生成断点 HookcreateMemo的定位非常纯粹不引入外部状态、不做订阅只做基于参数的纯函数结果缓存。二、快速上手斐波那契示例原文档给出的示例即是一个经典的昂贵计算——递归斐波那契数列。使用createMemo将fibonacci函数封装为useMemoFibonacciHookimport {createMemo} from react-use; const fibonacci n { if (n 0) return 0; if (n 1) return 1; return fibonacci(n - 1) fibonacci(n - 2); }; const useMemoFibonacci createMemo(fibonacci); const Demo () { const result useMemoFibonacci(10); return ( div fib(10) {result} /div ); };运行后页面渲染fib(10) 55。这里fibonacci(10)属于指数级复杂度的递归计算一旦把它包装进useMemoFibonacci同样的参数在后续渲染中会命中缓存而不再重复计算。这段示例在仓库中的 Storybook 里也有对应的可运行演示stories/createMemo.story.tsx其中同样用fibonacci封装了useMemoFibonacci并在 Demo 中渲染fib(10)的结果。你可以在本地执行yarn storybook对应 package.json 中的storybook脚本启动 Storybook 后在State/createMemo分组下查看文档与实时演示。三、API 形态createMemo的签名极其简洁原文档的 Reference 部分给出了核心形式const useMemoFn createMemo(fn);其中fn要被记忆化的纯函数类型约束为任意函数(...args: any) any返回值useMemoFn一个新的 React Hook接收与fn完全相同的参数返回fn的计算结果。从 src/factory/createMemo.ts 的源码可以看到完整的类型定义import { useMemo } from react; const createMemo T extends (...args: any) any(fn: T) (...args: ParametersT) useMemoReturnTypeT(() fn(...args), args); export default createMemo;这段代码揭示了几个值得注意的细节柯里化currying结构createMemo(fn)返回一个箭头函数该箭头函数接收...args: ParametersT即类型系统会从原函数T中自动提取参数类型列表返回值类型自动推导useMemoReturnTypeT显式声明了缓存结果的类型为原函数返回类型ReturnTypeT因此createMemo封装出的 Hook 在 TypeScript 下拥有完整的参数与返回值类型推断核心仅 3 行整个工厂实现本质上只是对 React 内置useMemo的一次封装。createMemo已由 src/index.ts 统一导出可直接通过import {createMemo} from react-use或按需引入react-use/lib/factory/createMemo使用。四、记忆化背后的原理参数即依赖createMemo之所以能工作是因为它把「原函数的所有参数」原封不动地作为了 ReactuseMemo的依赖数组useMemoReturnTypeT(() fn(...args), args);也就是说useMemoFibonacci(10)会被展开为useMemo(() fibonacci(10), [10])。当组件重新渲染时React 会对依赖数组做浅比较Object.is 语义只要参数数组中的每个值与上一次渲染时完全相同就直接复用上一次缓存的计算结果fn根本不会被调用只有任一参数发生变化才会重新执行fn并刷新缓存。这带来两个重要推论缓存粒度是参数组合参数的个数、顺序、值都参与比较useMemoFibonacci(10)与useMemoFibonacci(20)是两条独立的缓存闭包内的组件状态也会触发重算如果传入的参数中包含每次渲染都会变化的对象字面量、数组或内联函数浅比较必然不等缓存会失效——这是所有useMemo类缓存共有的限制并非createMemo特有。五、测试如何验证「不重复计算」仓库中的 tests/createMemo.test.ts 用 Jest 与testing-library/react-hooks精确验证了记忆化语义是理解该 Hook 行为的最佳旁证工厂产出的确实是函数expect(useMemoGetDouble).toBeInstanceOf(Function)确认createMemo(fn)的返回值是一个可调用的 Hook结果与原函数一致对参数1、3、5分别断言useMemoGetDouble(val)的结果与直接调用getDouble(val)相同同参数不重算第一次渲染传入5后getDouble被调用mockClear()之后用相同参数rerender()断言getDouble不再被调用命中缓存换参数重算将参数改为7后再次rerender()断言getDouble被重新调用缓存失效重新计算。这三条测试恰好对应记忆化的完整行为闭环首次计算 → 同参数复用 → 异参数失效从行为层面锁死了createMemo的正确性。六、与直接使用useMemo的对比以及适用边界维度useMemo直接使用createMemo封装书写成本每次组件内都要写useMemo(() fn(a, b), [a, b])工厂一次性封装组件内只需useMemoFn(a, b)复用性逻辑分散在各组件中同一条记忆化逻辑可被多个组件复用类型推导依赖与结果需手工维护参数/返回值类型从原函数自动推导本质React 内置缓存原语对useMemo的薄封装语义完全一致适用场景把昂贵的纯函数斐波那契、大数据排序、复杂格式化、正则编译、矩阵运算等提升为可在组件间复用的记忆化 Hook。需要注意的边界只适合纯函数createMemo只记忆结果不产生副作用。如果fn内部有副作用如写日志、发请求、修改外部状态副作用只会在首次计算时发生与预期可能不符参数需可浅比较对象、数组等引用类型参数若每次重建缓存将失去意义Hook 规则不变封装出的useMemoFn依然是标准 Hook只能在组件顶层或自定义 Hook 中调用不能出现在循环、条件分支中环境要求react-use 依赖 React Hooks API需要 React16.8.0或更高版本详见 docs/Usage.md如果你在使用 Webpack 等打包器时遇到 ES6 命名导入的依赖缺失报错可参考 docs/Usage.md 中关于按需引入与babel-plugin-import的配置说明将命名导入转换为react-use/lib/factory/createMemo这样的独立路径导入。七、小结createMemo是 react-use 中体积最小、语义最清晰的工厂之一三行核心源码见 src/factory/createMemo.ts、一组行为完备的测试见 tests/createMemo.test.ts和一份简明的文档见 docs/createMemo.md。它把 React 内置的useMemo抽象为「函数 → Hook」的一等转换让昂贵的纯函数能以极低的心智成本获得跨渲染、跨组件的复用能力。当你下次遇到「这个函数很贵我又不想在每个组件里重复写useMemo」的场景时createMemo就是那个开箱即用的答案。【免费下载链接】react-useReact Hooks — 项目地址: https://gitcode.com/gh_mirrors/re/react-use创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

ik_llama.cpp 最小示例 llama-simple 深度解析:从零构建文本生成管线

ik_llama.cpp 最小示例 llama-simple 深度解析:从零构建文本生成管线

ik_llama.cpp 最小示例 llama-simple 深度解析:从零构建文本生成管线 【免费下载链接】ik_llama.cpp llama.cpp fork with additional SOTA quants and improved performance 项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp 本篇文章围绕 i…

2026/9/19 8:03:35 阅读更多 →
从零搭建open-code-review:自动化代码评审的完整实践指南

从零搭建open-code-review:自动化代码评审的完整实践指南

周一早上十点,同事在群里扔了一条链接:"这个 PR 已经放三天了,有人能帮我看下吗?" 这种场景几乎每个研发团队都经历过。open-code-review 这个项目,最早就是为这件事做的自动化评审助理。它不追求取代人的判…

2026/9/19 8:02:35 阅读更多 →
Hermes Desktop 接入 Hindsight 长期记忆配置指南

Hermes Desktop 接入 Hindsight 长期记忆配置指南

Hermes Desktop 接入 Hindsight 长期记忆配置指南 【免费下载链接】hindsight Hindsight: Agent Memory That Learns 项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight Hermes Desktop 可以直接把 Hindsight 设为 Agent 的长期记忆提供方&#xff1…

2026/9/19 8:02:35 阅读更多 →

最新新闻

OAI数据集申请与下载全流程:从账号注册到DICOM处理

OAI数据集申请与下载全流程:从账号注册到DICOM处理

1. 为什么OAI数据集值得折腾这一整套流程如果你正在做医学影像相关的算法研究,尤其是骨关节、肌肉骨骼方向的深度学习项目,大概率绕不开OAI数据集。OAI全称Osteoarthritis Initiative,是一个长期跟踪膝关节骨关节炎的大规模公开研究队列&…

2026/9/20 12:02:23 阅读更多 →
ESP32音频abort残留问题与四层协同解决方案

ESP32音频abort残留问题与四层协同解决方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 12:02:23 阅读更多 →
GD32 MCU选型与开发实战:从内核架构到工程落地

GD32 MCU选型与开发实战:从内核架构到工程落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 12:02:23 阅读更多 →
深入 Compiler Explorer 构建系统架构:从 CMake 专用实现到可插拔的 BuildSystemDriver

深入 Compiler Explorer 构建系统架构:从 CMake 专用实现到可插拔的 BuildSystemDriver

深入 Compiler Explorer 构建系统架构:从 CMake 专用实现到可插拔的 BuildSystemDriver 【免费下载链接】compiler-explorer Run compilers interactively from your web browser and interact with the assembly 项目地址: https://gitcode.com/gh_mirrors/co/co…

2026/9/20 12:02:23 阅读更多 →
Pandoc 的 RST `class` 指令与标题属性合并:从 Issue 6699 到源码实现

Pandoc 的 RST `class` 指令与标题属性合并:从 Issue 6699 到源码实现

Pandoc 的 RST class 指令与标题属性合并:从 Issue #6699 到源码实现 【免费下载链接】pandoc Universal markup converter 项目地址: https://gitcode.com/gh_mirrors/pa/pandoc reStructuredText(RST)的 .. class:: 指令在 Pandoc 中…

2026/9/20 12:02:23 阅读更多 →
CANN ops-transformer GroupedMatMulAlltoAllv 算子实战:路由专家计算与 AlltoAllv 通信的融合方案

CANN ops-transformer GroupedMatMulAlltoAllv 算子实战:路由专家计算与 AlltoAllv 通信的融合方案

算子库人工智能深度学习Ascend 【免费下载链接】ops-transformer 本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。 项目地址: https://gitcode.com/cann/ops-transformer 点击查看 免费下载 导读 GroupedMatMulAlltoAllv 是 C…

2026/9/20 12:01:22 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →