从 Flux 到 Redux:重构 React 应用的指南
随着 React 技术的发展,前端开发人员越来越倾向于使用 Flux 或 Redux 这样的数据流解决方案来构建复杂的应用程序。虽然 Flux 是 React 中最常见的数据流框架之一,但越来越多的开发人员开始使用 Redux 来构建他们的应用程序。
Redux 被认为是 Flux 的更高级别实现,它通过提供单一不可变状态树来管理复杂的应用程序,从而使数据管理变得更加简单。在本指南中,我们将介绍如何将一个 Flux 应用程序重构为一个 Redux 应用程序,并描述 Redux 的基本原则和设计模式,以及如何在 React 中使用 Redux。
一步步重构你的 Flux 应用
为了更好地了解如何在您的 React 应用程序中使用 Redux,我们将提供一个简单的 Flux 应用,并一步步将其重构为 Redux 应用程序。
假设您有以下初始 Flux 应用程序:
app.jsx
-- -------------------- ---- ------- --- ----- - ----------------- --- -------- - --------------------- --- -------- - ------------------------------ --- ---------- - --------------------------------- --- ----------- - ------------------------------------- -------- -------------- - ------ - ------ ------------------------ ------ ------------------------ -- - --- --- - ------------------- ---------------- ---------- - ------ --------------- -- ------------------ ---------- - ------------------------------------------- -- --------------------- ---------- - ---------------------------------------------- -- ------- ---------- - ------ - ----- ------------ ------------------------------ -- ----- ------------------------ ------------------------ -- ------ -- -- ---------- ---------- - ------------------------------ -- ---------------- ------------- - -------------------------- -- --- -------------------- ------------------- --- --------------------------------展开代码
app-actions.js
-- -------------------- ---- ------- --- ------------- - ----------------------------------------- --- ------------ - -------------------------------------- --- ---------- - - ---------- ------------- - -------------------------------- ----------- ------------------------- ---- ---- --- -- -- -------------- - -----------展开代码
app-constants.js
var keyMirror = require('keymirror'); module.exports = keyMirror({ ADD_TO_CART: null, });
app-store.js
-- -------------------- ---- ------- --- ------------- - ----------------------------------------- --- ------------ - -------------------------------------- --- ------------ - ------------------------------- --- ------ - ------------------------- --- ------------ - --------- --- ---------- - --- -------- -------- - -- ----------------- - ---------------------- - ---- - --------------- - - ---- ---- ---- - -- - - -------- --------------- - ------ ---------------- - -------- ------------------- ---- - ------------------- -- ---- -- -------------------- --- -- - ---------------- - - --- -------- - ---------- ----------------------- - ----------- ---------- - ------------------------ -- ------------------ ------------------ - --------------------- ---------- -- --------------------- ------------------ - --------------------------------- ---------- -- ------------- ---------- - ------ ----------- -- ------------- ---------- - --- ----- - -- --- ---- --- -- ----------- - ----- -- ------------------- - ------------------------ - ------ ----------------- -- ---------------- ---------------------------------------- - --- ------ - --------------- ------ ------------------- - ---- ------------------------- ---------------- ------ -------- ------ ----- - ---------------------- ------ ----- --- --- -------------- - ---------展开代码
product-list.jsx
-- -------------------- ---- ------- --- ----- - ----------------- --- ---------- - ---------------------------------- --- ------- - --------------------- --- ----------- - ------------------- ------- ---------- - --- -------- - --------------------------------- -- - -------- ----------------- ---------------------------------- -- --- ------ ---------------------- -- ---------------- ------------- - -------------------------- -- --- -------------- - ------------展开代码
product.jsx
-- -------------------- ---- ------- --- ----- - ----------------- --- ------- - ------------------- ------- ---------- - ------ - ---- -------------------- ---- ---------------------------------------------------------- ---- ----------------------------------------------------------- ------- ---------------------------------- -- ------------- ------ -- -- ---------------- ---------- - ----------------------------------------------- -- --- -------------- - --------展开代码
在这个 Flux 应用中,我们有一个简单的购物车,用户可以将产品添加到购物车中并查看订单总额。让我们考虑如何将其转换为 Redux 应用程序。
重构 Flux 应用为 Redux 应用
Redux 与 Flux 之间的主要区别在于它提供了一个单一的可调用对象,即 Redux Store,该对象存储应用程序的状态。Redux Store 包含以下内容:
- State: 应用程序的当前状态
- Action: 描述应用程序状态更改的纯 JavaScript 对象
- Reducer: 描述状态如何响应操作的函数,接受当前状态和操作,并返回新状态的函数
我们将使用此模式重构 Flux 应用。让我们开始编写 Redux 应用的新入口点:index.jsx
。
index.jsx
-- -------------------- ---- ------- ------ ----- ---- -------- ------ -------- ---- ------------ ------ - -------- - ---- -------------- ------ - ----------- - ---- -------- ------ -------- ---- ---------------------- ------ --- ---- ------------------- ----- ----- - ---------------------- ---------------- --------- -------------- ---- -- ------------ ------------------------------ --展开代码
在这里,我们导入了 react-redux
中的 Provider
和 createStore
方法,以及我们应用程序的根 App
组件。我们使用 createStore
方法创建了 Redux Store,并将其作为参数传递给 Provider
组件,以使整个应用程序都可以访问 Store 中的状态数据。现在让我们看一下我们的新 app.jsx
组件。
app.jsx
-- -------------------- ---- ------- ------ ----- ---- -------- ------ ----------- ---- ----------------- ------ ---- ---- --------- ------ ------- ----- --- ------- --------------- - -------- - ------ - ----- ------------ -- ----- -- ------ -- - -展开代码
我们已经将所有关于 Flux Store 和 Action 的细节从 App 组件中移除,因为这些细节现在会作为将与 Store 和 Actions 相关的状态作为属性传递给子组件的方式来呈现。
接下来,我们将定义 actions 和 reducers,以描述应用程序中的状态与状态变化。
actions.js
export const ADD_TO_CART = 'ADD_TO_CART'; export function addToCart(sku) { return { type: ADD_TO_CART, sku, }; }
reducers.js
-- -------------------- ---- ------- ------ - --------------- - ---- -------- ------ - ----------- - ---- --------------------- -------- ---------- - - ------ --- ------ - -- ------- - --- ----- - --- --- ----- - -- ------ ------------- - ---- ------------ ----- - - -------------- -- -- ------------------- - ------------------------ - ---- - ----------------- - - ---- ----------- ---- - -- - --- ---- --- -- ------ - ----- -- -------------- - -------------------- - ------ - ------ ----- -- -------- ------ ------ - - ----- ----------- - ----------------- ----- --- ------ ------- ------------展开代码
现在让我们看看不同的单个组件:product-list.jsx
和 cart.jsx
。
product-list.jsx
-- -------------------- ---- ------- ------ ------ - --------- - ---- -------- ------ - ------- - ---- -------------- ------ - --------- - ---- --------------------- ------ ------- ---- ------------ ----- ----------- ------- --------------- - ------ --------- - - --------- --------------------------- ---------- -------------------------- -- -------- - ------ - ----- -------------------------- -- - -------- ----------- ----------- ---------------------------------- -- --- ------ -- - - -------- ---------------------- - ------ - --------- --------------- -- - ------ ------- ------------------------ - --------- ----------------展开代码
在这里,我们开辟了一个新的组件级状态,products
,并使用 -react-redux
中的 connect
方法将其绑定到父级 App
组件中的 Redux Store 上。
我们还定义了 addToCart
方法,并使用 connect
方法将其绑定到组件中。最后,我们将当前组件的 state
映射到 Store 的 state
。
cart.jsx
-- -------------------- ---- ------- ------ ------ - --------- - ---- -------- ------ - ------- - ---- -------------- ----- ---- ------- --------------- - ------ --------- - - ------ ---------------------------- ------ ---------------------------- -- -------- - ------ - ----- ---- -------------------------------------- -- - --- ---------- --------------------------- - --------------------- ----- --- ----- ----------- ------------------------- ------ -- - - -------- ---------------------- - ------ - ------ ----------------- ------ ----------------- -- - ------ ------- -------------------------------展开代码
在这里,我们定义了一个新的 cart
组件,并将 items
和 total
映射到 Store 的状态中。现在让我们看看我们在 product.jsx
组件中发生了什么。
product.jsx
-- -------------------- ---- ------- ------ ------ - --------- - ---- -------- ----- ------- ------- --------------- - ------ --------- - - -------- ---------------------------- ------------ -------------------------- -- -------- - ----- - ------ ------ --- - - ------------------- ------ - ---- -------------------- ---- --------------------------------------- ---- ---------------------------------------- ------- ---------------------------------------- --------- -- ------------- ------ -- - -------------------- - ---------------------------- - - ------ ------- --------展开代码
与之前的版本不同,我们将 onAddToCart
方法作为组件的 props 属性之一传递给子组件。因此,此组件现在可以称为“呈现组件”,它不知道任何有关 Flux 或 Redux 的内容。它只知道它如何渲染自己以及何时呼叫其他组件的方法。因此,这个组件是一个纯组件。
指导意义
通过以上演示,我们可以看到 Flux 和 Redux 都是优秀的数据流解决方案。但是,Redux 更加强大和有趣!Redux 改进了 Flux 的 Middleware 和 Store 的设计,提供了一个更优美的方式来管理不断变化的应用程序状态。
重构 Flux 应用程序以使用 Redux 很容易,因为 Redux 特别设计用于完全兼容 Flux 架构。我们可以通过编写拆分我们的应用程序逻辑成适当的 Actions 和 Reducers 代码块来增强应用程序的可读性和可维护性。
在设计 Redux 应用程序时,请记住以下准则:
- Store 中的状态应该是不可变的,这样才能保证应用程序状态的可重现性。
- 关于应用程序的状态变化发生的原因必须是一个 Action 对象。即,Redux 框架中的 Action 模型是在传递必要的信息的同时,保证更新状态数据可回溯构成。
- Reducers 是纯函数,一定得是“无副作用”和容易测试的功能。让 reducer始终保持一致,并不是针对某个操作实现计算和存储,只要 Action 利用处理的模型中,实现对应仅仅的变化即可。
- 进行“异构”数据序列化或者本地存储的操作是通过应用 Middleware 实现的。例如,Redux 让我们使用 Immutable.js 库的深层次值(类似 JSON 的对象)有状态检查/修复/传递的方式。
以上是 Redux 应用程序的基本设计规则。遵守这些原则可以帮助我们编写可维护和可预测的代码,在团队开发中将产生许多好处。
本文演示了如何使用一个“简单”的 Flux 应用程序为例来重构应用程序以实现更加灵活和可预测的 Redux 应用。
是的,人人都能使用并喜欢Redux。它提供了一个方便的开发范式,通过组合应用程序中的每个部分,从而使它更容易理解和维护。简而言之,Redux 是一种使您的 React 应用程序更好、更高效和更容易理解的方式。
附:示例代码
https://codesandbox.io/s/trendingweather-bbnhu
完成对指南的撰写,欢迎检查。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67b9977a306f20b3a680a6b2