Skip to main content

拆分 Reducer 逻辑

¥Splitting Up Reducer Logic

对于任何有意义的应用,将所有更新逻辑放入单个 reducer 函数中很快就会变得难以维护。虽然对于函数应该多长没有单一的规则,但人们普遍认为函数应该相对较短,并且最好只做一件特定的事情。因此,将很长的代码片段或执行许多不同操作的代码片段,并将其分解为更易于理解的较小片段,是一种很好的编程习惯。

¥For any meaningful application, putting all your update logic into a single reducer function is quickly going to become unmaintainable. While there's no single rule for how long a function should be, it's generally agreed that functions should be relatively short and ideally only do one specific thing. Because of this, it's good programming practice to take pieces of code that are very long or do many different things, and break them into smaller pieces that are easier to understand.

由于 Redux reducer 只是一个函数,因此同样的概念也适用。你可以将一些 reducer 逻辑拆分到另一个函数中,然后从父函数中调用该新函数。

¥Since a Redux reducer is just a function, the same concept applies. You can split some of your reducer logic out into another function, and call that new function from the parent function.

这些新功能通常属于以下三类之一:

¥These new functions would typically fall into one of three categories:

  1. 小型实用函数,包含多个地方需要的一些可重用逻辑块(实际上可能与特定业务逻辑相关,也可能不相关)

    ¥Small utility functions containing some reusable chunk of logic that is needed in multiple places (which may or may not be actually related to the specific business logic)

  2. 用于处理特定更新情况的函数,通常需要除典型 (state, action) 对之外的参数

    ¥Functions for handling a specific update case, which often need parameters other than the typical (state, action) pair

  3. 处理给定状态片的所有更新的函数。这些函数通常具有典型的 (state, action) 参数签名

    ¥Functions which handle all updates for a given slice of state. These functions do generally have the typical (state, action) parameter signature

为了清楚起见,这些术语将用于区分不同类型的功能和不同的用例:

¥For clarity, these terms will be used to distinguish between different types of functions and different use cases:

  • reducer:具有签名 (state, action) -> newState 的任何函数(即可以用作 Array.prototype.reduce 参数的任何函数)

    ¥reducer: any function with the signature (state, action) -> newState (ie, any function that could be used as an argument to Array.prototype.reduce)

  • 根 reducer:实际上作为第一个参数传递给 createStore 的 reducer 函数。这是 reducer 逻辑中唯一必须具有 (state, action) -> newState 签名的部分。

    ¥root reducer: the reducer function that is actually passed as the first argument to createStore. This is the only part of the reducer logic that must have the (state, action) -> newState signature.

  • 切片 reducer:用于处理对状态树的一个特定切片的更新的 reducer,通常通过将其传递给 combineReducers 来完成

    ¥slice reducer: a reducer that is being used to handle updates to one specific slice of the state tree, usually done by passing it to combineReducers

  • 案例功能:用于处理特定操作的更新逻辑的函数。这实际上可能是一个 reducer 函数,或者可能需要其他参数才能正常工作。

    ¥case function: a function that is being used to handle the update logic for a specific action. This may actually be a reducer function, or it may require other parameters to do its work properly.

  • 高阶 reducer:一个函数,它接受一个 reducer 函数作为参数,和/或返回一个新的 reducer 函数作为结果(例如 combineReducersredux-undo

    ¥higher-order reducer: a function that takes a reducer function as an argument, and/or returns a new reducer function as a result (such as combineReducers, or redux-undo)

术语 "sub-reducer" 也已在各种讨论中用于表示不是根 reducer 的任何函数,尽管该术语不是很精确。有些人还可能将某些函数称为 "商业逻辑"(与特定于应用的行为相关的函数)或 "效用函数"(不特定于应用的通用函数)。

¥The term "sub-reducer" has also been used in various discussions to mean any function that is not the root reducer, although the term is not very precise. Some people may also refer to some functions as "business logic" (functions that relate to application-specific behavior) or "utility functions" (generic functions that are not application-specific).

将复杂的流程分解为更小、更容易理解的部分通常用术语 功能分解 来描述。该术语和概念可以普遍应用于任何代码。然而,在 Redux 中,使用方法#3 构建 reducer 逻辑是很常见的,其中更新逻辑根据状态切片委托给其他函数。Redux 将此概念称为 reducer 组合,它是迄今为止使用最广泛的构造 reducer 逻辑的方法。事实上,Redux 包含一个名为 combineReducers() 的实用函数,该函数非常常见,它专门抽象了基于状态切片将工作委派给其他 reducer 函数的过程。然而,值得注意的是,它并不是唯一可以使用的模式。事实上,完全可以使用所有三种方法将逻辑拆分为函数,并且通常也是一个好主意。重构 reducer 部分显示了一些实际的示例。

¥Breaking down a complex process into smaller, more understandable parts is usually described with the term functional decomposition. This term and concept can be applied generically to any code. However, in Redux it is very common to structure reducer logic using approach #3, where update logic is delegated to other functions based on slice of state. Redux refers to this concept as reducer composition, and it is by far the most widely-used approach to structuring reducer logic. In fact, it's so common that Redux includes a utility function called combineReducers(), which specifically abstracts the process of delegating work to other reducer functions based on slices of state. However, it's important to note that it is not the only pattern that can be used. In fact, it's entirely possible to use all three approaches for splitting up logic into functions, and usually a good idea as well. The Refactoring Reducers section shows some examples of this in action.