@ngrx/store的createSelector()是否真的有必要使用?
完全懂你的感受!这种直接用this.store.select('media', 'games')的选择器写法确实清爽到不行——不用写一堆createSelector,也不用额外导入任何东西,几行代码就能搞定状态读取,初期开发效率拉满。
但项目规模一上来,问题就暴露了:所有选择器都堆在media.selectors.ts里,文件会变得越来越臃肿,满屏都是那种只做简单取值的选择器。原本一句this.store.select('media', 'games')就能搞定的事,现在得先import * as fromMedia from '../media',再写this.store.select(fromMedia.getAllGamesSelector()),其他场景也是同理,感觉反而多了一层没必要的中间层,徒增工作量。
针对这个痛点,分享几个实用的平衡方案:
模块化拆分选择器文件
别把所有media相关的选择器都塞在一个文件里,可以按功能维度拆分,比如单独创建media-games.selectors.ts、media-movies.selectors.ts,每个文件只负责对应模块的选择器。这样不仅文件体积变小,找起来更方便,导入的时候也可以只导入需要的那个选择器,不用全量导入整个fromMedia模块。用类型安全工具兼顾简洁性
如果担心字符串路径容易写错(毕竟没有类型提示),可以用NgRx的createFeatureSelector配合基础选择器,既保留接近原生的简洁性,又能获得类型检查:// media-games.selectors.ts import { createFeatureSelector, createSelector } from '@ngrx/store'; import { MediaState } from './media.state'; export const selectMediaState = createFeatureSelector<MediaState>('media'); export const selectGames = createSelector(selectMediaState, state => state.games);使用时只需要导入
selectGames即可:import { selectGames } from '../media/media-games.selectors'; // ... this.store.select(selectGames);比全量导入清爽很多,同时还能避免路径拼写错误。
根据场景灵活选择写法
不用一刀切要求所有状态读取都用单独的选择器:对于简单的、全局复用率低的状态读取,完全可以继续用this.store.select('media', 'games')这种简洁写法;而对于那些需要复用、或者涉及复杂状态组合(比如多个切片合并计算)的场景,再单独抽离选择器。这样既能保留初期的开发效率,又不会让选择器文件变得臃肿不堪。
内容的提问来源于stack exchange,提问作者Dolan

