Redux-Toolkit Query中selectFromResult与轮询的Selector使用是否正确?
问题描述
我正在使用Redux-Toolkit Query(RTKQ)的useMyApiQuery钩子从某API获取信息,设置每5秒轮询一次,并通过selectFromResult结合自定义Selector筛选所需数据。代码如下:
const selectorData = useMemo(() => { const emptyValue = {}, nullValue = null; return createSelector( [ (data) => data, (data, error) => (error ? error.status : -1), ], (data, status) => { if (status >= 400) return emptyValue; return data ?? nullValue; }, ); }, []); const { interestedData } = useMyApiQuery( args1, { selectFromResult: ({ data, error }) => { interestedData: selectorData(data, error) }), pollingInterval: 5000 } ); // using interestedData to load the data in UI.
我希望通过Selector避免组件每5秒重渲染,仅在数据或错误发生更新时触发重渲染,请问这种Selector的使用方式是否正确?
回答
你的思路是对的,但代码里有几个细节需要修正,才能真正实现避免不必要重渲染的目标:
selectFromResult的语法错误:你的箭头函数里没有用正确的对象字面量语法,应该添加括号包裹对象,确保返回值正确:selectFromResult: ({ data, error }) => ({ interestedData: selectorData(data, error) })原代码的写法没有返回对象,会导致
interestedData无法被正确解构。emptyValue的稳定性问题:你在useMemo内部定义了emptyValue = {},虽然当前useMemo的依赖是空数组不会重新计算,但这个对象每次创建时都是新的引用。如果后续API返回相同的400+错误,新的引用会触发组件不必要的重渲染。更稳妥的做法是把emptyValue用useMemo单独包裹,保证引用稳定:const emptyValue = useMemo(() => ({}), []); const nullValue = null; // 基本类型无需记忆化 const selectorData = useMemo(() => { return createSelector( [ (data) => data, (data, error) => (error ? error.status : -1), ], (data, status) => { if (status >= 400) return emptyValue; return data ?? nullValue; }, ); }, [emptyValue]);Selector的有效性:你用
createSelector创建的记忆化Selector是有效的——它会缓存计算结果,只有当输入的data或者error.status发生实际变化时,才会重新计算并返回新的结果。结合RTKQ的selectFromResult,组件只会在interestedData的引用或值发生真实变化时才会重渲染,而不是每次轮询都会触发(哪怕数据没有更新)。
总结:修正上述语法和引用稳定性问题后,这种方式是正确的,能够达到你想要的“仅在数据或错误更新时重渲染”的效果。
内容的提问来源于stack exchange,提问作者CodingEzio

