为什么在redux中纯函数reducer如此重要?

13

纯reducers没有副作用,可以实现时间旅行等功能。它们使得应用程序行为的推理更加容易。

这对我来说很直观,但我无法表达为什么纯reducers会带来这些积极的非功能属性。

有人能帮我表达一下,为什么让reducers无副作用会使得应用程序行为的推理更加容易吗?

是因为在运行reducers之后,保证了具有相同的状态吗?

如果是这样,那么即使是具有副作用的(即非纯)reducers也可能具有这个特性吗?


这是纯函数的基本属性,没错。不,你不能创建一个非纯函数,在对相同输入运行reducer后具有完全相同的状态。 - Bergi
1
我认为这个问题在软件工程SE上可能会得到更好的关注。无论如何,据我所知,缺乏副作用是推理更容易的原因,因为你所要注意的只是输入和输出 - 这些都是不言自明的。我没有将此作为答案发布,因为我不确定这种解释是否会对您产生循环推理的感觉。 - Dragomok
2个回答

15

这是因为运行 reducer 后保证状态完全相同吗?

是的,纯函数的 reducers 是 确定性的,这意味着如果它们得到相同的输入,它们将始终产生相同的输出结果。这个特性有助于像单元测试这样的情况,因为你知道如果一次测试通过,它总是会通过。

如果是这样,那么即使是具有副作用(即非纯函数)的 reducers 也可以具有这个属性吗?

不,非纯 reducers 将依赖于应用程序的 输入状态。虽然在测试时它们可能会以某种方式行为1000次,但在你从未想过测试的特定状态下,它们可能会出现故障。

当然,测试单元中可能会有一个遗漏的角落案例。但如果测试结果完全基于输入,那么只需查看 reducer 所期望的指定输入,就更有可能注意到这些角落案例。

如果一个函数改变了应用程序的状态,那么两次运行同一个函数,或者以不同的顺序运行相同的几个函数,可能会导致完全不同的行为。这使得很难推断应用程序的正确性,因为为了知道某一行代码是否正确,你必须知道在调用它之前发生了什么事情,可能是应用程序完全不同的部分。


啊,所以副作用是指将除了参数以外的任何东西视为输入,而不是改变返回值以外的状态?还是两者都可以? - Ben Aston
@BenAston:我没有表达得很准确。从技术上讲,副作用是关于改变状态的,但有一个隐含的假设,即如果您有一些函数改变状态,那么您可能也依赖于状态。如果您只改变了状态,但没有其他东西依赖于该状态,那么您的更改将是安全的,但毫无意义。如果您只依赖于状态,但应用程序的状态从未更改(即“状态”是恒定的),则情况相同。 - StriplingWarrior

2
“是的,这就是使纯减速器成为“黄金标准”的原因。如果输出仅取决于输入,则非常容易进行测试、回放、保留历史记录等操作。”
“(不是普遍的答案)。这也是正确的。如果你小心谨慎,非纯减速器也可以具有相同的属性。然而,这更容易出错,并且在概念上没有太多意义。我认为你想表达的是一切都只是输入和输出。你可以稍微改变思路,将“非纯”减速器的内部状态视为一个更多的输入。”
“在这种意义上,您可以想象跟踪您的应用程序状态、操作和减速器的内部状态,并最终获得与纯减速器相同的回放等属性(尽管您需要更多的代码来处理它)。”
“但是,现在问题来了:您现在有了实际应用程序状态和减速器的内部(隐藏)状态。谁想要跟踪两组状态?这才是真正使测试、推理和实现更加困难的地方。需要跟踪的“种类”更多,很容易忽略/忘记关键细节。从本质上讲,如果您已经有了大量应用程序来跟踪状态,为什么要在减速器中隐藏更多状态呢?”
“因此,即使忽略了为了“正确性”而做正确的事情,对于您的整个系统架构来说,在一个地方保留所有状态概念上更简单。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接