javascript - Redux:选择器模式的另一种实现
问题描述
以下示例显示了选择器模式的通常实现。然后我将讨论这个实现的问题。之后,我将建议另一种可能有用的实现。
通常的实现:
下面是 root reducer 和公共选择器的样子:
// reducers/index.js
import { combineReducers } from 'redux';
import * as Items from './items';
import * as Login from './login';
export default combineReducers({
login: Login.reducer,
items: Items.reducer
// more slices ...
});
// PUBLIC SELECTORS
export const getToken = state => Login.getToken(state.login);
export const getLoginError = state => Login.getError(state.login);
export const isLoginLoading = state => Login.isLoading(state.login);
export const getItems = state => Items.getToken(state.items);
export const getCurrentItem = state => Items.getError(state.items);
export const isItemsLoading = state => Items.isLoading(state.items);
// Selectors for data from other slices
// ...
// Selectors for derived data from multiple slices
export const getOwnedItems = (state) => {
// ...
};
以下是切片缩减器及其私有选择器的外观:
// reducers/login.js
import {
// actions ...
} from '../actions';
const defaultState = {
// ...
};
export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};
// PRIVATE SELECTORS
export const getToken = state => state.token;
export const getError = state => state.error;
export const isLoading = state => state.loading;
另一个切片缩减器及其私有选择器:
// reducers/items.js
import {
// actions ...
} from '../actions';
const defaultState = {
// ...
};
export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};
// PRIVATE SELECTORS
export const getItems = state => state.items;
export const getCurrentItem = state => state.currentItem;
export const isItemsLoading = state => state.isLoading;
这个实现的用法是这样的:
import { getLoginError, isLoginLoading } from '../reducers';
const mapStateToProps = state => {
return {
error: getLoginError(state),
loading: isLoginLoading(state)
};
};
问题:
之前的选择器实现要求所有公共选择器都定义在reducers/index.js
. 请注意,公共选择器接收由定义的根 reducer 管理的完整状态reducers/index.js
。
公共选择器可以分为两种类型。提取选择器仅用于从状态中提取数据。以及从状态计算派生信息的派生信息选择器。对于用户来说,所有选择器都是相同的,它们的目的是将客户端代码与状态的形状分开。
先前实现的第一个问题是所有提取选择器都被写入了两次。一次作为公共选择器,另一个作为私有选择器,公共选择器调用私有选择器。
第二个问题是特定切片的所有私有选择器只能接收该切片,但它被传递了很多次,一次用于该切片的私有选择器的每个使用实例,这似乎是重构的好案例。
以下是可能证明有用的选择器的另一种实现:
另一种实现
根 reducer 文件将仅提供一个select()
获取完整状态的函数,并提供公共接口,客户端代码可以从该接口中检索状态中的数据。
接口可能由函数或按名称分组的函数集合组成。这种结构允许我们提供一个接口,除了能够提供更多定制的公共选择器之外,该接口将使提取选择器的实现变得微不足道。
请不要将选择器的结构与状态的形状混淆。两者之间没有耦合。即使状态的形状发生了变化,公共选择器仍然可以为应用程序实现相同的接口。
这是select(state)
函数中实现的公共选择器:
// reducers/index.js
import { combineReducers } from 'redux';
import * as Items from './items';
import * as Login from './login';
export default combineReducers({
login: Login.reducer,
items: Items.reducer
// more slices ...
});
// PUBLIC SELECTORS
export const select = (state) => {
return {
login: Login.select(state.login),
items: Items.select(state.items),
// Selectors for drived data from multiple slices
getOwnedItems: () => {
// ...
}
};
};
这是以相同方式实现的私有选择器:
// reducers/login.js
import {
// actions ...
} from '../actions';
const defaultState = {
// ...
};
export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};
// PRIVATE SELECTORS
export const select = (state) => {
return {
getToken: () => state.token,
getError: () => state.error,
isLoading: () => state.loading
};
};
再次为另一个切片:
// reducers/items.js
import {
// actions ...
} from '../actions';
const defaultState = {
// ...
};
export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};
// PRIVATE SELECTORS
export const select = (state) => {
return {
getItems: () => state.items,
getCurrentItem: () => state.currentItem,
isLoading: () => state.loading
};
};
此实现的用法如下所示:
import { select } from '../reducers';
const mapStateToProps = state => {
return {
error: select(state).login.getError(),
loading: select(state).login.isLoading()
};
};
问题一:
这种实现的缺点是什么?
问题2:
是否有其他方法可以解决上述问题?
谢谢
解决方案
推荐阅读
- c# - 将值设置为 DataGridViewComboBox Winforms C#
- java - 使用数据框在 Java 中对 Spark 中的 n 列求和
- amazon-web-services - Cloudberry - 无法安装驱动器
- neo4j - 如何使用 Cypher 返回具有不同属性的节点的所有属性
- angular - 如何将从下拉多选接收的数组值转换为角度5中的字符串
- reactjs - 如何使用 React 路由而不是 express
- android - Ionic 3 键盘在横向模式下隐藏输入字段
- c# - C# 将往返日期字符串转换为 DateTime 对象
- mysql - SQL 使用查询不同的条件
- wordpress - 主目录 HTML 和子目录 WordPress 网站上的非 www 到 www 重定向不起作用