当前位置: 首页
前端开发
@ngrx/store MemoizedSelector 详解

@ngrx/store MemoizedSelector 详解

热心网友 时间:2026-06-12
转载

1 认识 Memoized Selector 的核心价值 在 @ngrx store featureState someData ); 这里的 memoizedSelector 会先从 featureSelector 获取 featureState,然后只提取出 someData 部分。如果输入

1. 认识 Memoized Selector 的核心价值

@ngrx/storeMemoizedSelector 是尤为关键的核心概念,也是优化 Angular 应用性能的利器。简而言之,它借助 reselect 库,让状态选择器拥有“记忆”能力——缓存计算结果,避免重复执行计算逻辑。如此一来,应用的响应速度与运行效率都能够获得显著提升。

详解什么是@ngrx/store开发包中的MemoizedSelector

接下来,本文将带你深入剖析 MemoizedSelector 的工作原理、具体用法,以及它在真实项目中所带来的切实收益。最后,会通过一个完整的购物车示例,帮助你轻松将理论落实为代码实践。

在 Redux 应用中,状态管理的地位不言而喻。@ngrx/store 让 Angular 项目能够无缝接入 Redux 模式。而选择器(Selector)正是那把钥匙——用于从状态树中精准提取所需的数据片段。选择器允许我们集中组织状态的读取逻辑,显著提升代码的复用性。

@ngrx/store 中,选择器主要分为两种类型:

  • 普通选择器:每次调用都会重新计算并返回全新结果。如果状态处理逻辑较为复杂,频繁调用极易引发性能瓶颈。
  • Memoized 选择器:基于 reselect 实现,内部内置缓存机制。只要输入条件没有发生变化,就会直接返回缓存结果,而不会重新执行计算。这正是性能优化的关键所在。

2. Memoized Selector 的用法详解

在 Angular 项目中,我们主要通过 createFeatureSelectorcreateSelector 这两个函数来定义 Memoized 选择器。前者用于锁定某个 feature 模块的状态,后者则用于创建具体的记忆化选择器。

2.1 创建 Feature 选择器(createFeatureSelector)

createFeatureSelector 接收一个特征标识符(字符串),返回一个选择器函数,该函数能从根状态中提取出对应 feature 模块下的完整状态片段。

import { createFeatureSelector } from '@ngrx/store';

const featureSelector = createFeatureSelector('featureName');

上面这段代码创建了一个名为 featureSelector 的 Feature 选择器,并将其绑定到 'featureName' 标识符。之后只需调用它,就能直接获取 featureName 模块下的全部状态内容。

2.2 创建 Memoized 选择器(createSelector)

createSelector 是真正的核心函数。它接收若干个输入选择器(可以是 Feature 选择器或其他 Memoized 选择器),然后附加一个输出函数,用于从输入结果中提取或计算最终所需的数据。

import { createSelector } from '@ngrx/store';

const memoizedSelector = createSelector(
  featureSelector,
  (featureState) => featureState.someData
);

这里的 memoizedSelector 会先从 featureSelector 获取 featureState,然后只提取出 .someData 部分。如果输入条件(即 featureState 对象引用)没有发生变化,它会直接返回上次缓存的结果,不再重复执行读取操作。

2.3 使用 Memoized 选择器

实际使用非常自然——像调用普通函数一样调用选择器,然后将其交给 store 的 select 方法即可。

store.select(memoizedSelector).subscribe((data) => {
  console.log('Selected data:', data);
});

当状态发生变化时,memoizedSelector 会自动判断是否需要重新计算;只有依赖的输入发生了变更,才会产生新结果。这保证了组件不会因为无关的状态改动而频繁重渲染。

3. Memoized Selector 的核心优势

清楚了用法之后,再聊聊它究竟强在哪里。

3.1 显著提升性能

记忆化缓存直接省掉了大量重复计算。特别是在大型应用或复杂的状态推导场景中,效果立竿见影。输入条件不变时,结果直接取自缓存,响应速度自然大幅提升。

3.2 减少不必要的状态更新

由于缓存机制的存在,只有当真正依赖的数据发生改变时,选择器才会返回新值。这能够有效降低组件和管道的重新渲染次数,整个应用因此运行更加流畅。

3.3 支持复杂的状态计算

通过组合多个选择器和输出函数,你可以轻松实现多层嵌套的状态转换。而缓存机制能确保这种复杂计算仅在必要时执行,不会白白浪费性能资源。

3.4 提升代码复用与组织能力

将状态选择逻辑从组件中剥离出来,集中到选择器文件中,然后在多个组件间复用。组件变得更加轻量,维护成本也直线下降。

4. 实例:使用 Memoized 选择器管理购物车状态

理论讲再多,不如一个实际例子来得直观。下面我们用购物车场景来演示 Memoized 选择器如何高效管理复杂状态。

假设购物车包含多个商品,每个商品有 ID、名称、价格和数量。购物车状态则是所有商品的集合。

先定义接口:

interface CartItem {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

interface CartState {
  items: CartItem[];
  total: number;
}

接着创建 NgRx 特性模块,定义 action 和 reducer。

// 购物车 actions 文件
import { createAction, props } from '@ngrx/store';
import { CartItem } from './cart-state.interface';

export const addToCart = createAction(
  '[Cart] Add To Cart',
  props<{ item: CartItem }>()
);

export const removeFromCart = createAction(
  '[Cart] Remove From Cart',
  props<{ itemId: number }>()
);

// 购物车 reducer 文件
import { createReducer, on } from '@ngrx/store';
import { CartState, CartItem } from './cart-state.interface';
import { addToCart, removeFromCart } from './cart.actions';

const initialState: CartState = {
  items: [],
  total: 0,
};

export const cartReducer = createReducer(
  initialState,
  on(addToCart, (state, { item }) => {
    const existingItem = state.items.find((i) => i.id === item.id);
    if (existingItem) {
      const updatedItems = state.items.map((i) =>
        i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
      );
      return {
        ...state,
        items: updatedItems,
        total: state.total + item.price,
      };
    } else {
      const newItem: CartItem = { ...item, quantity: 1 };
      return {
        ...state,
        items: [...state.items, newItem],
        total: state.total + item.price,
      };
    }
  }),
  on(removeFromCart, (state, { itemId }) => {
    const updatedItems = state.items.filter((i) => i.id !== itemId);
    const removedItem = state.items.find((i) => i.id === itemId);
    return {
      ...state,
      items: updatedItems,
      total: state.total - (removedItem ? removedItem.price * removedItem.quantity : 0),
    };
  })
);

然后是最关键的部分——创建 Memoized 选择器:

// 购物车选择器文件
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { CartState } from './cart-state.interface';

export const selectCartState = createFeatureSelector('cart');

export const selectCartItems = createSelector(
  selectCartState,
  (cartState) => cartState.items
);

export const selectCartTotal = createSelector(
  selectCartState,
  (cartState) => cartState.total
);

在组件中使用这些选择器,就像呼吸一样自然:

// 购物车组件文件
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { CartItem } from './cart-state.interface';
import { addToCart, removeFromCart } from './cart.actions';
import { selectCartItems, selectCartTotal } from './cart.selectors';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-cart',
  template: `
    

Shopping Cart

{{ item.name }} - Quantity: {{ item.quantity }} - Price: ${{ item.price }}

Total Price: ${{ cartTotal$ | async }}

`, }) export class CartComponent { cartItems$: Observable; cartTotal$: Observable; constructor(private store: Store) { this.cartItems$ = this.store.select(selectCartItems); this.cartTotal$ = this.store.select(selectCartTotal); } addItemToCart(item: CartItem) { this.store.dispatch(addToCart({ item })); } removeItemFromCart(itemId: number) { this.store.dispatch(removeFromCart({ itemId })); } }

组件通过 store.select 订阅了 selectCartItemsselectCartTotal 这两个 Memoized 选择器,模板中使用 async 管道实时展示数据。当用户添加或删除商品时,只有真正依赖的状态片段发生变更,选择器才会推送新值,组件也随之更新。整个过程既高效又清晰。

5. 总结

MemoizedSelector@ngrx/store 中一个非常实用的特性,它通过记忆化机制极大优化了状态选择器的性能。借助 createFeatureSelectorcreateSelector,你可以轻松组合出复杂但高效的状态提取逻辑。

在实际项目中,将状态选择逻辑抽象为可复用的 Memoized 选择器,既能让组件保持简洁,又能提升整体性能。当然,也要注意避免滥用——如果创建过多细粒度的选择器,反而会增加内存开销。在性能与维护性之间找到平衡,才是最佳实践。

来源:https://www.jb51.net/javascript/293737mw3.htm

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
DCloud平台选型指南 适用场景与核心差异详解

DCloud平台选型指南 适用场景与核心差异详解

DCloud是一个围绕跨平台开发与流应用构建的技术生态,旨在帮助前端开发者使用Web技术开发高性能移动应用。其核心产品包括集成开发环境HBuilderX和基于Vue js的uni-app框架,支持一套代码发布至iOS、Android、Web及多端小程序。相比ReactNative和Flutter,uni-app在多端覆盖和Vue技术栈学习成本上具有优势,适合

时间:2026-07-10 06:47
DCloud使用教程与常见问题解决方案详解

DCloud使用教程与常见问题解决方案详解

DCloud提供跨平台应用开发方案,核心为HBuilderX与uni-app框架。开发者使用Vue js语法编写代码,可编译发布至iOS、Android、Web及小程序等多端。流程涵盖项目创建、开发调试与真机预览。常见问题如设备识别、编译失败等可通过检查设置、查看日志与条件编译解决。应用完成后支持云打包生成安装包。

时间:2026-07-10 06:47
DCloud新手入门教程 从零开始快速掌握开发技巧

DCloud新手入门教程 从零开始快速掌握开发技巧

DCloud是一个基于Web技术的跨平台应用开发平台,允许开发者使用HTML5等语言编写代码,并编译为iOS、Android及小程序应用,实现“一次编写,多端发布”。开发需使用HBuilderX,基于Vue js进行页面开发,平台提供丰富组件与API,并支持插件市场扩展功能。

时间:2026-07-10 06:47
DCloud新手入门指南从零开始了解这个开发平台

DCloud新手入门指南从零开始了解这个开发平台

DCloud是一个移动应用开发平台,旨在帮助前端开发者使用Web技术高效开发性能接近原生的跨平台应用。其核心产品包括HBuilderX开发环境和基于Vue js的uni-app框架,可实现一次开发、多端发布。平台通过完整工具链和插件生态降低开发门槛,适合需要快速迭代、覆盖多端的应用场景。

时间:2026-07-10 06:47
Zepto实战项目优化技巧与应用场景详解

Zepto实战项目优化技巧与应用场景详解

Zepto js作为轻量级JavaScript库,专为移动端优化,体积仅约10KB。它支持模块化定制,可按需构建以减小体积。使用时需减少DOM操作、善用事件委托,并可混合原生API提升性能。Zepto能融入现代工程流,但需注意其与jQuery的API差异及兼容性限制,适合在移动端性能优先的场景中替代jQuery。

时间:2026-07-10 06:47
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜