在Redux Toolkit的extraSelectors中调用兄弟选择器报错的咨询
Redux Toolkit createFeature extraSelectors 兄弟选择器调用问题
问题描述
在Redux Toolkit的createFeature配置的extraSelectors中,尝试在兄弟选择器selectFirstFilteredBook内调用selectFilteredBooks时,触发错误:Cannot access 'selectFirstFilteredBook' before initialization。
示例代码:
export const booksFeature = createFeature({ name: 'books', reducer: createReducer( initialState, on(BookListPageActions.search, (state, action) => ({ ...state, query: action.query, })), ), extraSelectors: ({ selectQuery, selectBooks }) => ({ selectFilteredBooks: createSelector( selectQuery, selectBooks, (query, books) => books.filter(book => book.title.includes(query)), ), selectFirstFilteredBook: createSelector( // 触发错误的选择器 selectFilteredBooks, (filteredBooks) => filteredBooks[0], ), }), });
原因分析
这是预期行为,并非Redux Toolkit的限制,本质是JavaScript对象字面量的初始化特性导致的:
- 在对象字面量中定义属性时,属性按顺序逐个创建。当创建
selectFirstFilteredBook时,selectFilteredBooks还未被添加到当前对象中,无法通过对象属性的方式访问。 - 错误提示的表述容易混淆,实际核心问题是当前对象的
selectFilteredBooks属性尚未完成初始化。
解决方案
无需重复选择器逻辑,只需调整选择器的定义方式,利用函数作用域的变量实现互相引用:
方案:先定义选择器变量,再返回对象
将选择器先在函数作用域内定义为变量,再统一放到返回对象中,变量之间可自由引用,不受对象属性初始化顺序限制:
export const booksFeature = createFeature({ name: 'books', reducer: createReducer( initialState, on(BookListPageActions.search, (state, action) => ({ ...state, query: action.query, })), ), extraSelectors: ({ selectQuery, selectBooks }) => { // 先在函数作用域内定义所有选择器变量 const selectFilteredBooks = createSelector( selectQuery, selectBooks, (query, books) => books.filter(book => book.title.includes(query)), ); const selectFirstFilteredBook = createSelector( selectFilteredBooks, (filteredBooks) => filteredBooks[0], ); // 再返回包含所有选择器的对象 return { selectFilteredBooks, selectFirstFilteredBook, }; }, });
这种方式既保持了选择器的复用性,又符合JavaScript语法规则,是最优雅的解决办法。
内容的提问来源于stack exchange,提问作者Max Tuzenko
相关产品推荐
相关产品推荐

