重新选择多实例记忆
Reselect multiple instance memoization
我使用 React/Redux/Reselect.
从 reselect doc 开始,如果我有多个组件将使用具有不同参数的选择器,我需要为每个实例创建一个。
const makeGetVisibleTodos = () => {
return createSelector(
[
(state, props) => props.visibilityFilter,
state => state.todos,
],
(visibilityFilter, todos) => {
return todos.filter(td => td.visibility === visibilityFilter)
}
}
)
}
但在我的例子中,listId
可能来自多个来源(例如 props.listId
、props.location.match.listId
、props.location.search.listId
等)
所以我更喜欢这样写:
const makeGetVisibleTodos = listId => {
return createSelector(
[
state => state.todos,
],
(todos) => {
todos.filter(td => td.listId === listId)
}
}
)
}
并按以下方式连接:
connect(
(state, ownProps) => ({
offerer: makeGetVisibleTodos(ownProps.location.match.listId)(state, ownProps),
}),
)
我很确定它可以工作,但我不是 100% 确定它会正确记忆:
如果两个组件用相同的 listId
调用 makeGetVisibleTodos
,它们将有 2 个不同的缓存值,对吗?这不是我想要的...
这个怎么样?
const makeGetVisibleTodos = listId => {
return createSelector(
state => state.todos,
state => listId,
(todos, listId) => {
todos.filter(td => td.listId === listId)
}
}
)
}
在这种情况下,makeGetVisibleTodos(ownProps.listId)
和makeGetVisibleTodos(ownProps.match.params.listId)
共享相同的缓存值,当ownProps.listId === ownProps.match.params.listId
?
或者另一种表达问题的方法是:如何传递不会(直接)依赖于 state
和 ownProps
但在记忆过程中检查是否相等的额外参数?
我还可以扩展 ownProps
:
connect(
(state, ownProps) => ({
offerer: makeGetVisibleTodos()(state, Object.assign({}, ownProps, {listId: ownProps.location.match.listId}),
}),
)
但是觉得超级丑而且没重点了...
您的方法不会正确地进行记忆,因为当您调用 makeGetVisibleTodos
时总是会创建一个新的选择器。你可以通过写
来改进它
const listIdQuerySelector = (state, props) => {
return props.match.params && props.match.params.listId;
};
const todoSelector = createSelector(
[
listIdQuerySelector,
state => state.todos,
],
(listId, todos) => {
todos.filter(td => td.listId === listId)
}
}
)
并像
一样使用它
connect(
(state, ownProps) => ({
offerer: makeGetVisibleTodos(state, ownProps),
}),
)
在您上面发布的示例中,记忆将无法正常工作,因为您每次调用 mapStateToProps
函数时都会创建一个重新选择选择器的新实例。
请注意文档中的 mapStateToProps
函数如何也成为工厂函数 (makeMapStateToProps
) 并且 makeGetVisibleTodos
在返回实际的 mapStateToProps
函数之前被调用,例如所以。
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props)
}
}
return mapStateToProps
}
此外,您不会在 makeGetVisibleTodos()
调用中传递您在选择器中使用的道具,而是在实际调用选择器本身时传递。
这会导致类似
的结果
const makeGetVisibleTodos = () => {
return createSelector(
state => state.todos,
state => (_, listId), // Here you have access to all the arguments passed
(todos, listId) => {
todos.filter(td => td.listId === listId)
}
}
)
}
然后你可以这样写选择器:
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props.params.match.listId),
todos2: getVisibleTodos(state, props.listId),
todos3: getVisibleTodos(state, 'hardcodedListId')
}
}
return mapStateToProps
}
作为 re-reselect(reselect
的小包装)的作者,我想指出库将如何解决您的用例。
re-reselect
提供开箱即用的选择器,它保留 跨不同组件的记忆 。
import createCachedSelector from 're-reselect';
const getVisibleTodos = createCachedSelector(
state => state.todos,
(state, listId) => listId,
(todos, listId) => {
todos.filter(td => td.listId === listId)
}
}
)(
(todos, listId) => listId, // Create/use a different selector for each different listId
);
像普通选择器一样使用它(在任何不同的容器组件中)而忘记选择器工厂:
const makeMapStateToProps = () => {
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props.params.match.listId),
todos2: getVisibleTodos(state, props.listId),
todos3: getVisibleTodos(state, 'hardcodedListId')
}
}
return mapStateToProps
}
此用例也在 re-reselect docs 中描述。
我使用 React/Redux/Reselect.
从 reselect doc 开始,如果我有多个组件将使用具有不同参数的选择器,我需要为每个实例创建一个。
const makeGetVisibleTodos = () => {
return createSelector(
[
(state, props) => props.visibilityFilter,
state => state.todos,
],
(visibilityFilter, todos) => {
return todos.filter(td => td.visibility === visibilityFilter)
}
}
)
}
但在我的例子中,listId
可能来自多个来源(例如 props.listId
、props.location.match.listId
、props.location.search.listId
等)
所以我更喜欢这样写:
const makeGetVisibleTodos = listId => {
return createSelector(
[
state => state.todos,
],
(todos) => {
todos.filter(td => td.listId === listId)
}
}
)
}
并按以下方式连接:
connect(
(state, ownProps) => ({
offerer: makeGetVisibleTodos(ownProps.location.match.listId)(state, ownProps),
}),
)
我很确定它可以工作,但我不是 100% 确定它会正确记忆:
如果两个组件用相同的 listId
调用 makeGetVisibleTodos
,它们将有 2 个不同的缓存值,对吗?这不是我想要的...
这个怎么样?
const makeGetVisibleTodos = listId => {
return createSelector(
state => state.todos,
state => listId,
(todos, listId) => {
todos.filter(td => td.listId === listId)
}
}
)
}
在这种情况下,makeGetVisibleTodos(ownProps.listId)
和makeGetVisibleTodos(ownProps.match.params.listId)
共享相同的缓存值,当ownProps.listId === ownProps.match.params.listId
?
或者另一种表达问题的方法是:如何传递不会(直接)依赖于 state
和 ownProps
但在记忆过程中检查是否相等的额外参数?
我还可以扩展 ownProps
:
connect(
(state, ownProps) => ({
offerer: makeGetVisibleTodos()(state, Object.assign({}, ownProps, {listId: ownProps.location.match.listId}),
}),
)
但是觉得超级丑而且没重点了...
您的方法不会正确地进行记忆,因为当您调用 makeGetVisibleTodos
时总是会创建一个新的选择器。你可以通过写
const listIdQuerySelector = (state, props) => {
return props.match.params && props.match.params.listId;
};
const todoSelector = createSelector(
[
listIdQuerySelector,
state => state.todos,
],
(listId, todos) => {
todos.filter(td => td.listId === listId)
}
}
)
并像
一样使用它connect(
(state, ownProps) => ({
offerer: makeGetVisibleTodos(state, ownProps),
}),
)
在您上面发布的示例中,记忆将无法正常工作,因为您每次调用 mapStateToProps
函数时都会创建一个重新选择选择器的新实例。
请注意文档中的 mapStateToProps
函数如何也成为工厂函数 (makeMapStateToProps
) 并且 makeGetVisibleTodos
在返回实际的 mapStateToProps
函数之前被调用,例如所以。
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props)
}
}
return mapStateToProps
}
此外,您不会在 makeGetVisibleTodos()
调用中传递您在选择器中使用的道具,而是在实际调用选择器本身时传递。
这会导致类似
的结果const makeGetVisibleTodos = () => {
return createSelector(
state => state.todos,
state => (_, listId), // Here you have access to all the arguments passed
(todos, listId) => {
todos.filter(td => td.listId === listId)
}
}
)
}
然后你可以这样写选择器:
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props.params.match.listId),
todos2: getVisibleTodos(state, props.listId),
todos3: getVisibleTodos(state, 'hardcodedListId')
}
}
return mapStateToProps
}
作为 re-reselect(reselect
的小包装)的作者,我想指出库将如何解决您的用例。
re-reselect
提供开箱即用的选择器,它保留 跨不同组件的记忆 。
import createCachedSelector from 're-reselect';
const getVisibleTodos = createCachedSelector(
state => state.todos,
(state, listId) => listId,
(todos, listId) => {
todos.filter(td => td.listId === listId)
}
}
)(
(todos, listId) => listId, // Create/use a different selector for each different listId
);
像普通选择器一样使用它(在任何不同的容器组件中)而忘记选择器工厂:
const makeMapStateToProps = () => {
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props.params.match.listId),
todos2: getVisibleTodos(state, props.listId),
todos3: getVisibleTodos(state, 'hardcodedListId')
}
}
return mapStateToProps
}
此用例也在 re-reselect docs 中描述。