0

0

Reselect 中使用闭包实现带参选择器的性能陷阱与正确用法

霞舞

霞舞

发布时间:2025-12-26 11:15:08

|

600人浏览过

|

来源于php中文网

原创

Reselect 中使用闭包实现带参选择器的性能陷阱与正确用法

在 reselect 中,通过闭包(如 `customerid => createselector(...)`)创建带参数的选择器会导致每次渲染都生成新实例,使 memoization 完全失效,引发重复计算和内存浪费;而官方推荐的多参数 `createselector` 方式才能真正复用缓存。

Reselect 的核心价值在于共享、可复用、带缓存的选择器实例。其 memoization 机制依赖于两个关键前提:

  1. 选择器函数是稳定引用(即不随渲染重新创建)
  2. 输入参数能被正确捕获并参与缓存键计算

❌ 错误方式:闭包工厂模式(性能陷阱)

// 危险!每次调用 selectOrdersByCustomer(customerId) 都创建全新 selector 实例
const selectOrdersByCustomer = customerId =>
  createSelector(
    state => state.orders,
    orders => {
      console.count('⚠️ output selector executed'); // 每次渲染都触发!
      return orders.filter(order => order.customerId === customerId);
    }
  );

// 在组件中:
const orders = useSelector(selectOrdersByCustomer(customerId));

该写法看似简洁,实则违背 Reselect 设计原则:

  • selectOrdersByCustomer(customerId) 每次调用返回一个全新的 createSelector 实例
  • 每个实例拥有独立的缓存(recomputations()、memoizedResultSelector),互不共享;
  • 即使 state.orders 和 customerId 均未变化,因 selector 实例不同,缓存永远无法命中 → 输出选择器反复执行,且返回新数组(=== false)
✅ 实验验证(见原答案日志):三次调用 selectOrdersByCustomer2(1)(state) 导致输出选择器执行 3 次,且结果引用不等(false false)。

✅ 正确方式:多参数选择器(推荐标准写法)

// ✅ 稳定声明:单个 selector 实例,支持参数化输入
const selectOrdersByCustomer = createSelector(
  state => state.orders,
  (state, customerId) => customerId, // 第二个输入选择器,接收 props 参数
  (orders, customerId) => {
    console.count('✅ memoized output selector'); // 仅当 orders 或 customerId 变化时执行
    return orders.filter(order => order.customerId === customerId);
  }
);

// 在组件中(useSelector 自动透传第二个参数):
const orders = useSelector(state => selectOrdersByCustomer(state, customerId));

此方式优势显著:

京点点
京点点

京东AIGC内容生成平台

下载
  • selectOrdersByCustomer 是单一、稳定的函数引用,可安全定义在模块顶层;
  • Reselect 内部将 (state, customerId) 作为缓存键(equalityCheck 默认为 ===),确保相同参数组合命中缓存;
  • 多次调用 selectOrdersByCustomer(state, 1) 仅首次执行过滤逻辑,后续直接返回缓存结果(=== true)。

⚠️ 注意事项与最佳实践

  • 避免在组件内部或 useSelector 回调中动态创建 selector(包括闭包、useMemo(() => createSelector(...)) 等);
  • 若需动态生成 selector(极少数场景),应配合 useMemo 缓存 factory 函数本身,并确保 customerId 是 useMemo 的依赖项——但通常没必要,优先用多参数模式;
  • 对于复杂参数(如对象),注意 Reselect 默认浅比较(===),必要时自定义 memoize 或 equalityCheck;
  • 使用 createSelectorCreator + lodash.memoize 可扩展缓存策略,但默认方案已满足绝大多数场景。

总结

闭包式 selector 不是“稍慢一点”,而是彻底丢失 memoization 能力——它把 Reselect 降级为普通纯函数,还额外增加了 selector 创建开销。务必坚持 Reselect 官方范式:参数通过输入选择器传入,selector 实例全局唯一、稳定复用。这是保障 React-Redux 应用高性能的关键细节之一。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

133

2025.07.29

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

84

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

24

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

35

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

16

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

56

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

16

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

9

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.7万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号