如何正确使用createSelector缓存遍历对象的Redux选择器?
我写了这样一个Redux选择器:
const selectListOfApplicationIdAndApplicationCompany = state => Object.values(state.applications.dict) .map((x) => ({ "id": x.id, "companyName": x.companyName }) );
React提示这个选择器需要缓存,因为相同输入参数会返回不同的对象。我理解原因,但看了Redux的createSelector文档还是不知道怎么正确缓存它。
我试了下面的写法:
export const selectListOfApplicationIdAndApplicationCompany = createSelector( [_selectListOfApplicationIdAndApplicationCompany], (data) => data );
结果收到警告:
The result function returned its own inputs without modification. e.g
createSelector([state => state.todos], todos => todos)This could
lead to inefficient memoization and unnecessary re-renders. Ensure
transformation logic is in the result function, and extraction logic
is in the input selectors.
文档提到「输入选择器」和「输出选择器」,但我搞不清原选择器哪部分属于输入、哪部分属于输出,也不确定能不能拆分。
正确的缓存写法
要解决这个问题,核心是把选择器拆成明确的两部分:
- 输入选择器:只负责从state里提取原始的、未加工的数据,这里就是
state.applications.dict这个字典对象 - 结果函数:负责把原始数据转换成你需要的结构(也就是原来的
Object.values遍历+map转换逻辑)
这样createSelector会自动缓存结果函数的返回值:只有当输入选择器提取的原始字典引用发生变化时,才会重新执行转换逻辑;否则直接返回缓存的结果对象,避免每次调用都生成新数组/新对象,从而解决重复渲染问题。
正确代码如下:
import { createSelector } from '@reduxjs/toolkit' // 输入选择器:提取原始的applications字典 const selectApplicationsDict = state => state.applications.dict // 带缓存的目标选择器 export const selectListOfApplicationIdAndApplicationCompany = createSelector( [selectApplicationsDict], // 传入输入选择器数组 (applicationsDict) => { // 结果函数:在这里完成数据转换 return Object.values(applicationsDict).map(x => ({ id: x.id, companyName: x.companyName })) } )
为什么之前的写法会触发警告
你之前的写法是把已经完成转换的新数组作为输入选择器的返回值,然后结果函数直接返回这个输入。这种情况下,输入选择器每次调用都会生成新数组(map必然返回新引用),createSelector会判定输入每次都变化,缓存完全起不到作用,所以才会提示你要把「数据提取逻辑」放在输入选择器,「数据转换逻辑」放在结果函数里。
内容的提问来源于stack exchange,提问作者user23145140

