在使用 React 和 Redux 开发项目时,我们经常需要定义 reducer 来管理应用的状态。一个 reducer 对应一个 state,并定义了其如何响应 action。然而,在实际开发中,有时候我们需要管理多个 state,而这些 state 的结构可能是相似的,这时候我们就可以使用一个 higher-order reducer 来封装这一部分逻辑。
typed-redux-kit.mapped-reducer
是一个用 TypeScript 编写的 higher-order reducer,它可以映射多个子 reducer 的输出,将它们整合到一个 parent state 中。它的设计灵感来自于 scaled-redux 和 map-reducers 这两个库。
本文将介绍如何使用 typed-redux-kit.mapped-reducer
,并提供示例代码。
安装
你可以使用 npm
或 yarn
安装 typed-redux-kit.mapped-reducer
npm install typed-redux-kit.mapped-reducer
或
yarn add typed-redux-kit.mapped-reducer
示例
假设我们有这样两个 state:
-- -------------------- ---- ------- --------- --------- - ----- ------- ---- ------- - --------- ------------ - --- ------- ----- ------- ------ ------- -
我们可以定义两个 reducer 分别对应这两个 state:
-- -------------------- ---- ------- -------- ------------------ ---------- ------- -------- --------- - ------ ------------- - ---- ----------- ------ - --------- ----- --------------- -- ---- ---------- ------ - --------- ---- --------------- -- -------- ------ ------ - - -------- --------------- ------ ------------- ------- ------ -- ------------ - ------ ------------- - ---- ----------- ------ - --------- ----- --------------- -- ---- ------------ ------ - --------- ------ --------------- -- -------- ------ ------ - -
现在,我们想要将这两个 state 合并到一个 parent state 中,定义一个新的 reducer:
-- -------------------- ---- ------- ------ - ------------- - ---- --------------------------------- ---- --------- - - ----- ---------- -------- ------------- -- ----- ------------- --------- - - ----- - ----- --- ---- -- -- -------- - --- -- ----- --- ------ -- -- -- ----- ----------- - --------------------------- - ----- ------------ -------- --------------- ---
在这个例子中,我们将 initialState
定义为一个对象,包含两个子 state:user
和 product
。我们使用 mappedReducer
函数来将这两个子 reducer 映射到 parent reducer 中。
现在我们就可以在组件中使用这个 reducer 了:
const [state, dispatch] = useReducer(rootReducer, initialState);
深入理解
上面的示例中我们简单介绍了如何使用 mappedReducer
,现在让我们来看看更多的使用场景和 API。
传递额外参数
在实际开发中,我们可能需要传递一些额外的参数给子 reducer。例如,在用户登录时,我们需要将用户信息传递给 userReducer
,在后端返回订单列表时,我们需要将订单列表传递给 productReducer
。这时候我们可以使用 mappedReducer
的第二个参数来传递这些参数。
-- -------------------- ---- ------- ----- ----------------- ---------------- - - ----- --- ---- -- --------- ------ -- ----- -------------------- ------------------- - - --- -- ----- --- ------ -- ------- --- -- ----- ----------- - --------------------------- - ----- ------- ------- - ---- -- -- ------------------ ------- - ---- --- -------- ------- ------- - ------ -- -- --------------------- ------- - ------ --- ---
我们将 userReducer
和 productReducer
的第三个参数都命名为 { user }
和 { orders }
,这样在调用 reducer 时,这些参数就会被传递给它们。
合并多个 reducer
mappedReducer
的第二个参数可以是一个对象,也可以是一个函数。如果是一个对象,表示将子 reducer 映射到指定的子 state 中;如果是一个函数,表示将多个子 reducer 合并到一起。
假设我们有这样三个 state:
-- -------------------- ---- ------- --------- --------- - ----- ------- - --------- ------------ - ----- ------- ------ ------- - --------- ---------- - --------- --------------- -
我们可以定义三个 reducer 分别对应这三个 state:
-- -------------------- ---- ------- -------- ------------------ ---------- ------- -------- --------- - ------ - --------- ----- ----------- --- -------------- - -------------- - ----------- -- - -------- --------------- ------ ------------- ------- ------ -- ------------ - ------ - --------- ----- ----------- --- ------------------ - -------------- - ----------- ------ ----------- --- ------------------- - -------------- - ------------ -- - -------- ------------------- ----------- ------- -------- ---------- - ------ - --------- --------- ----------- --- ------------- - ------------------- - ----- --- ------ - -- - ---------------------- -- -- - --- -------------------- - ----------------- ------- - ----------------- - ---------- -------- --------- -- -- -- -
在这里,我们的需求是将 product
state 下的多个 product 映射到 orders
state 中,而 user
state 则需要单独处理。我们可以使用 mergeReducers
函数来将这些 reducer 合并到一起。
-- -------------------- ---- ------- ------ - ------------- - ---- --------------------------------- ---- --------- - - ----- ---------- ------- ----------- -- ----- ----------- - --------------------------- - ----- ------------ ------- --------------- --------------- ------- - ------ ------------------- ------- - -------------------- ------- - ------ - ----- ------------ -------- - ------ ------------------ -- -- -- --- -- --- ---
在这里,我们使用 mergeReducers
函数来将 productReducer
和 orderReducer
合并到一起,并将结果映射到 orders.products
中。这时候,我们需要在 orderReducer
中处理 UPDATE_PRODUCT
这个 action,因为 productReducer
并不能智能地处理这个 action。我们使用 updateProduct
函数来包装 UPDATE_PRODUCT
,将 index
和其他参数一起传递给它。
现在我们可以在组件中使用这个 reducer:
-- -------------------- ---- ------- ----- ------- --------- - ----------------------- -------------- ----- --------- - ----------- ----- ------------- - ---------------------- ----- ---------- - -- -- ---------- ----- ------------- --- ----- -------------- - ------ ------- -- ---------- ----- --------------- -------- ---- --- ----- ----------------- - ------- ------- ----- ------- -- ---------- ----- ---------------------- -------- - ------ ---- - --- ----- ------------------ - ------- ------- ------ ------- -- ---------- ----- ----------------------- -------- - ------ ----- - ---
类型声明
通过 mappedReducer
和 mergeReducers
函数,我们可以尽可能地减少代码重复,提高代码复用性和可维护性。但是,当我们使用 TypeScript 开发时,我们也需要保持类型安全。
typed-redux-kit.mapped-reducer
会自动生成合并后 state 和 action 的类型声明。我们定义 RootState
时,可以直接使用 ReturnType<typeof rootReducer>
得到类型声明:
type RootState = ReturnType<typeof rootReducer>;
这样,在我们使用 useReducer
函数时,state
和 dispatch
的类型声明就会自动推导出来。
结语
在这篇文章中,我们介绍了如何使用 typed-redux-kit.mapped-reducer
来管理多个 state,并提供了详细的示例代码。希望本文对你理解 higher-order reducer 有所帮助!如果你想要了解更多关于 Redux 的内容,可以查看 Redux 官方文档和 React 官方文档。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6005605d81e8991b448de80e