const someSelector = createSelector( getUserIdsSelector,(ids) => ids.map((id) => yetAnotherSelector(store,id),); // ^^^^^ (yetAnotherSelector expects 2 args)
那个另一个选择器是另一个选择器,它接受用户id-id并返回一些数据.
但是,由于它是createSelector,我无权访问它(我不希望它作为一个函数,因为memoization不会工作).
有没有办法在createSelector中以某种方式访问存储?或者有没有其他方法来处理它?
编辑:
我有一个功能:
const someFunc = (store,id) => { const data = userSelector(store,id); // ^^^^^^^^^^^^ global selector return data.map((user) => extendUserDataSelector(store,user)); // ^^^^^^^^^^^^^^^^^^^^ selector }
这样的功能正在杀死我的应用程序,导致所有内容重新渲染并让我疯狂.帮助赞赏.
!然而:
我做了一些基本的自定义memoization:
import { isEqual } from 'lodash'; const memoizer = {}; const someFunc = (store,id); if (id in memoizer && isEqual(data,memoizer(id)) { return memoizer[id]; } memoizer[id] = data; return memoizer[id].map((user) => extendUserDataSelector(store,user)); }
解决方法
我遇到了与你相同的情况,遗憾的是没有找到一种从另一个选择器的身体调用选择器的有效方法.
我说有效的方法,因为你总是可以有一个输入选择器,它传递整个状态(存储),但这会在每个状态的变化上重新计算你的选择器:
const someSelector = createSelector( getUserIdsSelector,state => state,(ids,state) => ids.map((id) => yetAnotherSelector(state,id) )
途径
但是,我发现了两种可能的方法,用于下面描述的用例.我想你的情况类似,所以你可以采取一些见解.
所以情况如下:你有一个选择器,它通过id从Store获取特定用户,并且选择器返回特定结构中的User.让我们说getUserById选择器.现在一切都很好,很简单.但是当您希望通过其ID获取多个用户并且还重用以前的选择器时,会出现问题.我们将它命名为getUsersByIds选择器.
1.始终使用数组,输入id值
第一种可能的解决方案是让一个总是需要一个id数组的选择器(getUsersByIds)和一个重用前一个的数组,但它只能获得1个User(getUserById).因此,当您只想从商店获得1个用户时,您必须使用getUserById,但您必须传递一个只有一个用户ID的数组.
这是实施:
import { createSelectorCreator,defaultMemoize } from 'reselect' import { isEqual } from 'lodash' /** * Create a "selector creator" that uses `lodash.isEqual` instead of `===` * * Example use case: when we pass an array to the selectors,* they are always recalculated,because the default `reselect` memoize function * treats the arrays always as new instances. * * @credits https://github.com/reactjs/reselect#customize-equalitycheck-for-defaultmemoize */ const createDeepEqualSelector = createSelectorCreator( defaultMemoize,isEqual ) export const getUsersIds = createDeepEqualSelector( (state,{ ids }) => ids),ids => ids) export const getUsersByIds = createSelector(state => state.users,getUsersIds,(users,userIds) => { return userIds.map(id => ({ ...users[id] }) } ) export const getUserById = createSelector(getUsersByIds,users => users[0])
用法:
// Get 1 User by id const user = getUserById(state,{ ids: [1] }) // Get as many Users as you want by ids const users = getUsersByIds(state,{ ids: [1,2,3] })
2.重新使用选择器的主体,作为独立功能
这里的想法是在独立函数中分离选择器主体的公共部分和可重用部分,因此该功能可以从所有其他选择器中调用.
这是实施:
export const getUsersByIds = createSelector(state => state.users,userIds) => { return userIds.map(id => _getUserById(users,id)) } ) export const getUserById = createSelector(state => state.users,(state,props) => props.id,_getUserById) const _getUserById = (users,id) => ({ ...users[id]})
用法:
// Get 1 User by id const user = getUserById(state,{ id: 1 }) // Get as many Users as you want by ids const users = getUsersByIds(state,3] })
结论
方法#1.具有较少的样板(我们没有独立的功能)并且具有干净的实现.
方法#2.更可重复使用.想象一下,当我们调用选择器时,我们没有用户的id,但我们从选择器的主体中获取它作为关系.在这种情况下,我们可以轻松地重用独立功能.这是一个伪示例:
export const getBook = createSelector(state => state.books,state => state.users,(books,users,id) => { const book = books[id] // Here we have the author id (User's id) // and out goal is to reuse `getUserById()` selector body,// so our solution is to reuse the stand-alone `_getUserById` function. const authorId = book.authorId const author = _getUserById(users,authorId) return { ...book,author } }