如何将指定ngRx选择器改为直接返回布尔值?该方式是否正确?
如何将Redux Selector从返回过滤后的数据集改为直接返回布尔值?
我现在用下面这个Selector来返回指定日期范围内的数据集,然后在组件里只能通过判断返回列表的长度来给变量赋值true或false。我想知道怎么修改这个Selector让它直接返回布尔值,而且这种做法是否合理?
原代码:
export const selectModel = (planedDate: Date) => createSelector( selectDrugReviews, (reviews: ReviewModel[]) => reviews.filter(date => date.startDateTime.getTime() <= planedDate.getTime() && (date.endDateTime !== undefined ? date.endDateTime.getTime() >= planedDate.getTime() : true)) );
当然可以这么改,而且这种做法不仅正确,还更符合Selector的设计意图——把派生状态的计算逻辑集中在Selector里,组件只需要直接使用最终的布尔值即可,不用再做额外的判断。
修改方法
核心是把filter()换成some()方法:filter()会返回所有符合条件的元素组成的数组,而some()会遍历数组,只要有一个元素满足条件就立刻返回true,遍历结束都没满足就返回false,这刚好和你在组件里判断列表长度 > 0的逻辑完全等价。
修改后的代码:
export const selectHasMatchingReview = (planedDate: Date) => createSelector( selectDrugReviews, (reviews: ReviewModel[]) => reviews.some(review => review.startDateTime.getTime() <= planedDate.getTime() && (review.endDateTime ? review.endDateTime.getTime() >= planedDate.getTime() : true) ) );
为什么这么做是对的?
- 逻辑完全一致:
some()的判断逻辑和你原有的过滤条件完全相同,只要存在至少一个符合日期范围的review,就返回true,和你判断filteredList.length > 0的结果完全一样。 - 性能更优:
some()是短路遍历——找到第一个符合条件的元素就会停止遍历,而filter()会遍历整个数组并生成新数组,在数据量大的时候some()的性能更好。 - 利用Selector的缓存:Redux的
createSelector会对计算结果进行缓存,只有当selectDrugReviews返回的reviews数组或者传入的planedDate发生变化时,才会重新计算布尔值。如果你在组件里判断长度,每次组件render都要重新执行一次长度判断(虽然开销不大,但Selector的缓存能进一步优化)。
额外小优化
可以把日期比较的逻辑抽成一个小函数,让代码更清晰:
const isReviewInDateRange = (review: ReviewModel, targetDate: Date) => { const targetTime = targetDate.getTime(); return review.startDateTime.getTime() <= targetTime && (review.endDateTime ? review.endDateTime.getTime() >= targetTime : true); }; export const selectHasMatchingReview = (planedDate: Date) => createSelector( selectDrugReviews, (reviews: ReviewModel[]) => reviews.some(review => isReviewInDateRange(review, planedDate)) );
这样代码可读性更高,也方便后续维护或者复用这个日期判断逻辑。
内容的提问来源于stack exchange,提问作者uma
相关产品推荐
相关产品推荐

