从 redux 存储中获取数据到简单函数的最佳实践方法是什么?
What is the best practice approach to getting data from the redux store into a simple function?
假设我有一个名为 calculateFees
的函数,它需要从后端发送一些数据,例如 consultingFee
。它看起来像:
const calculateFees = itemPrice => itemPrice * [consultingFee]
[consultingFee]
是一个占位符,因为我不确定如何从 redux 商店获取它。我们还假设 calculateFees
要复杂得多,它有大约 10 多种费用,并且被几十个组件使用。我能想到的选项是:
1) 传入调用它的连接到 redux 状态的 class 的所有费用。
(例如 calculateFees(itemPrice, feeOne, feeTwo, FeeThree, ...)
2) 复制每个连接到 redux 状态的 class 中的代码。
3) 导出整个商店(或其中的一部分),以便 calculateFees
函数可以通过导入访问数据。
4) 不确定这是否可能,但是使用静态方法创建一个 class,并将其连接到 redux 存储。然后使用它,例如 MyCompanyFees.calculateFees
.
5) 创建一个仅从状态中提取数据的 thunk,以及 returns 计算的费用。使用它似乎不正确,因为它不是异步的,也不会更新状态树。
我想获得一些关于最佳实践方法的指导/建议,因为我不喜欢 1、2 或 3。
一个简单的 calculation/utility 函数不应该知道它的数据来自哪里,应该只接受它作为参数:
const calculateFees = (itemPrice, consultingFee) => itemPrice * consultingFee
如果数据来自商店,那么 calculateFees
应该在选择器中调用。
选择器:
const getCalculatedFees = (state, { itemId }) => {
const itemPrice = state.items[itemId].price;
const consultingFee = state.consultingFee;
return calculateFees(itemPrice, consultingFee);
}
然后选择器可以被组件或与动作相关的函数使用,例如 thunks 和 sagas。
组件:
connect(
state => ({
calculatedFees: getCalculatedFees(state)
})
)(MyComponent)
砰砰声:
const myAction = itemId => (dispatch, getState) => {
const calculatedFee = getCalculatedFees(getState(), { itemId });
// do stuff...
dispatch(doSomethingElse(calculatedFee));
}
传奇:
function* mySaga({ itemId }) {
const calculatedFee = yield select(getCalculatedFees, { itemId });
// ...
}
我想说这在很大程度上取决于特定的用例,比如这些值(意味着计算函数的输入)可以改变的频率(是购物车之类的东西还是更像是生成的报告之类的东西)事情,当你获取一次数据时就是这样)并且如果它只是每个视图的一个计算或多个具有不同输入的计算(例如你必须计算 table 中每一行的费用)。
首先,计算应该是一个单独的函数,它获取它需要的所有数据作为参数(这样你也可以很容易地对它进行单元测试)并且不关心它是否在 React 应用程序中使用或者你是否重新使用 Redux 或其他任何东西。如果您认为它将使用相同的参数多次调用,您还可以阅读称为记忆的概念,但我想在大多数情况下,记忆应该发生在这个函数之外。
现在,假设您的商店中已有其余数据(您提到的 consultingFee
占位符),并且希望在收到后端响应后计算出值。在这种情况下,您可以从存储中提取值,如 bsapaka 的答案所示,并将计算出的值放入 redux 存储中,您可以在需要的地方访问。如果您发出一次请求,显示计算值就足够了,仅此而已,您知道如果您需要再次计算它,您将有不同的输入值并且必须再次调用后端并且您不需要缓存结果,尽管我认为如果是这种情况,您根本不应该将计算出的值存储在您的商店中。
您还可以在 mapStateToProps 函数中进一步使用选择器,reselect 库对此很有用(请务必阅读 README 的 "Sharing Selectors with Props Across Multiple Component Instances" 部分)。这样,您就拥有了分派操作的组件,该操作从后端获取您需要的数据并将其放入 redux 存储中。在 mapStateToProps 中,您使用 memoized 选择器收集它需要的所有数据并计算结果,除非输入(在这种情况下来自 redux 存储的相关值)发生变化,否则不会重新计算。我更喜欢这种方法,因为它减少了 redux 中的副作用,并且对我来说更具声明性,但我也更喜欢将 redux 用作具有原始值的缓存,如果我需要从中派生值,我会使用 memoized 选择器。
假设我有一个名为 calculateFees
的函数,它需要从后端发送一些数据,例如 consultingFee
。它看起来像:
const calculateFees = itemPrice => itemPrice * [consultingFee]
[consultingFee]
是一个占位符,因为我不确定如何从 redux 商店获取它。我们还假设 calculateFees
要复杂得多,它有大约 10 多种费用,并且被几十个组件使用。我能想到的选项是:
1) 传入调用它的连接到 redux 状态的 class 的所有费用。
(例如 calculateFees(itemPrice, feeOne, feeTwo, FeeThree, ...)
2) 复制每个连接到 redux 状态的 class 中的代码。
3) 导出整个商店(或其中的一部分),以便 calculateFees
函数可以通过导入访问数据。
4) 不确定这是否可能,但是使用静态方法创建一个 class,并将其连接到 redux 存储。然后使用它,例如 MyCompanyFees.calculateFees
.
5) 创建一个仅从状态中提取数据的 thunk,以及 returns 计算的费用。使用它似乎不正确,因为它不是异步的,也不会更新状态树。
我想获得一些关于最佳实践方法的指导/建议,因为我不喜欢 1、2 或 3。
一个简单的 calculation/utility 函数不应该知道它的数据来自哪里,应该只接受它作为参数:
const calculateFees = (itemPrice, consultingFee) => itemPrice * consultingFee
如果数据来自商店,那么 calculateFees
应该在选择器中调用。
选择器:
const getCalculatedFees = (state, { itemId }) => {
const itemPrice = state.items[itemId].price;
const consultingFee = state.consultingFee;
return calculateFees(itemPrice, consultingFee);
}
然后选择器可以被组件或与动作相关的函数使用,例如 thunks 和 sagas。
组件:
connect(
state => ({
calculatedFees: getCalculatedFees(state)
})
)(MyComponent)
砰砰声:
const myAction = itemId => (dispatch, getState) => {
const calculatedFee = getCalculatedFees(getState(), { itemId });
// do stuff...
dispatch(doSomethingElse(calculatedFee));
}
传奇:
function* mySaga({ itemId }) {
const calculatedFee = yield select(getCalculatedFees, { itemId });
// ...
}
我想说这在很大程度上取决于特定的用例,比如这些值(意味着计算函数的输入)可以改变的频率(是购物车之类的东西还是更像是生成的报告之类的东西)事情,当你获取一次数据时就是这样)并且如果它只是每个视图的一个计算或多个具有不同输入的计算(例如你必须计算 table 中每一行的费用)。
首先,计算应该是一个单独的函数,它获取它需要的所有数据作为参数(这样你也可以很容易地对它进行单元测试)并且不关心它是否在 React 应用程序中使用或者你是否重新使用 Redux 或其他任何东西。如果您认为它将使用相同的参数多次调用,您还可以阅读称为记忆的概念,但我想在大多数情况下,记忆应该发生在这个函数之外。
现在,假设您的商店中已有其余数据(您提到的 consultingFee
占位符),并且希望在收到后端响应后计算出值。在这种情况下,您可以从存储中提取值,如 bsapaka 的答案所示,并将计算出的值放入 redux 存储中,您可以在需要的地方访问。如果您发出一次请求,显示计算值就足够了,仅此而已,您知道如果您需要再次计算它,您将有不同的输入值并且必须再次调用后端并且您不需要缓存结果,尽管我认为如果是这种情况,您根本不应该将计算出的值存储在您的商店中。
您还可以在 mapStateToProps 函数中进一步使用选择器,reselect 库对此很有用(请务必阅读 README 的 "Sharing Selectors with Props Across Multiple Component Instances" 部分)。这样,您就拥有了分派操作的组件,该操作从后端获取您需要的数据并将其放入 redux 存储中。在 mapStateToProps 中,您使用 memoized 选择器收集它需要的所有数据并计算结果,除非输入(在这种情况下来自 redux 存储的相关值)发生变化,否则不会重新计算。我更喜欢这种方法,因为它减少了 redux 中的副作用,并且对我来说更具声明性,但我也更喜欢将 redux 用作具有原始值的缓存,如果我需要从中派生值,我会使用 memoized 选择器。