我有一个选择器:
const someSelector = createSelector(
getUserIdsSelector,
(ids) => ids.map((id) => yetAnotherSelector(store, id),
); // ^^^^^ (yetAnotherSelector expects 2 args)
该
yetAnotherSelector
是另一个选择器,它使用用户ID-id
并返回一些数据。但是,因为它是
createSelector
,所以我无权在其中存储(我不希望将它作为函数使用,因为那时备忘录无法正常工作)。有什么办法可以在
createSelector
内部访问存储吗?还是有其他方法可以解决?编辑:
我有一个功能:
const someFunc = (store, id) => {
const data = userSelector(store, id);
// ^^^^^^^^^^^^ global selector
return data.map((user) => extendUserDataSelector(store, user));
// ^^^^^^^^^^^^^^^^^^^^ selector
}
这种功能正在杀死我的应用程序,导致所有内容重新渲染并让我发疯。帮助表示赞赏。
!!然而:
我已经完成了一些基本的自定义备注:
import { isEqual } from 'lodash';
const memoizer = {};
const someFunc = (store, id) => {
const data = userSelector(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,并且选择器以特定的结构返回User。假设
getUserById
选择器。到目前为止,一切都很好,也很简单。但是,当您想通过其ID获取多个用户并重用先前的选择器时,就会出现问题。让我们将其命名为getUsersByIds
选择器。1.始终使用数组作为输入id值
第一种可能的解决方案是有一个选择器,该选择器始终期望一个id数组(
getUsersByIds
),第二个选择器重复使用前一个ID,但只能获得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.重用选择器的主体,作为独立功能
这里的想法是在一个独立的函数中分离选择器主体的公共(public)部分和可重用部分,因此可以从所有其他选择器中调用此函数。
这是实现:
export const getUsersByIds = createSelector(state => state.users, getUsersIds,
(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, { ids: [1, 2, 3] })
结论
方法#1。 的样板更少(我们没有独立功能),并且实现干净。
方法2。 更可重用。想象一下,在调用选择器时没有用户ID的情况,但是我们从选择器的主体获取它的关系。在这种情况下,我们可以轻松地重用独立功能。这是一个伪示例:
export const getBook = createSelector(state => state.books, state => state.users, (state, props) => props.id,
(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
}
}
关于javascript - 重新选择-调用另一个选择器的选择器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50965013/