如何在 Redux reducer 中使用 Reselect 选择器
How to use Reselect selectors inside a Redux reducer
我的应用程序已经有大量可供各种容器对象使用的选择器。这些非常适合访问状态的不同部分并使重构状态变得更加容易。
现在我想在我的一些 reducer 函数中使用我的选择器。问题是在 reducer 内部,state
参数指的是状态的特定切片,而选择器函数期望用状态根对象调用。
人为的例子:
/* Selectors */
const getTodos = state => state.todos;
const getUncompletedTodos = createSelector(
[ getTodos ],
todos => todos.filter(t => !t.completed)
);
/* Reducer */
const todosReducer = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
];
case 'REMOVE_COMPLETED_TODOS':
return getUncompletedTodos(state); // <-- this won't work
}
}
您的选择器从根状态对象开始工作。
要伪造这个你可以做
return getUncompletedTodos({todos: state});
但恕我直言,更好的主意是重用过滤功能
/* Selectors */
const getTodos = state => state.todos;
const filterCompleted = todos => todos.filter(t => !t.completed)
const getUncompletedTodos = createSelector(
[ getTodos ],
filterCompleted
);
// inside reducer
case 'REMOVE_COMPLETED_TODOS':
return filterCompleted(state);
Yury 的回答有效,但没有利用记忆(见评论)。如果你想要那样,解决方案是只为它需要的状态片编写选择器。
选择器将变为:
const getUncompletedTodos = createSelector(
[todos => todos], // Not sure if there's a way to skip this redundancy and still take advantage of memoization with reselect.
todos => todos.filter(t => !t.completed)
);
在减速器中,你可以像这样简单地使用它:
case 'REMOVE_COMPLETED_TODOS':
return getUncompletedTodos(state);
然而,当在其他地方使用根状态上的选择器时,您可以这样使用它:
getUncompletedTodos(state.todos)
我看到的唯一缺点是你必须记住用状态的正确部分调用选择器,当然如果你正确使用 TypeScript,它会提醒你这一点。
我的应用程序已经有大量可供各种容器对象使用的选择器。这些非常适合访问状态的不同部分并使重构状态变得更加容易。
现在我想在我的一些 reducer 函数中使用我的选择器。问题是在 reducer 内部,state
参数指的是状态的特定切片,而选择器函数期望用状态根对象调用。
人为的例子:
/* Selectors */
const getTodos = state => state.todos;
const getUncompletedTodos = createSelector(
[ getTodos ],
todos => todos.filter(t => !t.completed)
);
/* Reducer */
const todosReducer = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
];
case 'REMOVE_COMPLETED_TODOS':
return getUncompletedTodos(state); // <-- this won't work
}
}
您的选择器从根状态对象开始工作。
要伪造这个你可以做
return getUncompletedTodos({todos: state});
但恕我直言,更好的主意是重用过滤功能
/* Selectors */
const getTodos = state => state.todos;
const filterCompleted = todos => todos.filter(t => !t.completed)
const getUncompletedTodos = createSelector(
[ getTodos ],
filterCompleted
);
// inside reducer
case 'REMOVE_COMPLETED_TODOS':
return filterCompleted(state);
Yury 的回答有效,但没有利用记忆(见评论)。如果你想要那样,解决方案是只为它需要的状态片编写选择器。
选择器将变为:
const getUncompletedTodos = createSelector(
[todos => todos], // Not sure if there's a way to skip this redundancy and still take advantage of memoization with reselect.
todos => todos.filter(t => !t.completed)
);
在减速器中,你可以像这样简单地使用它:
case 'REMOVE_COMPLETED_TODOS':
return getUncompletedTodos(state);
然而,当在其他地方使用根状态上的选择器时,您可以这样使用它:
getUncompletedTodos(state.todos)
我看到的唯一缺点是你必须记住用状态的正确部分调用选择器,当然如果你正确使用 TypeScript,它会提醒你这一点。