Redux和Vuex的区别
前言
对于任何应用,在自身数据传递中, state
扮演了重要的角色。随着应用扩增, 状态管理也变的复杂,使用中央仓库管理应用的数据也迫在眉睫。中央仓库可以让 state
的管理更加简单、原子化以及方便扩展。
在本文中,我们将仔细研究并比较当前前端生态系统中两个最流行的状态管理库: Redux
和 Vuex
。
什么是状态管理,为什么需要它?
状态管理是在应用的组件间读取和变更 state
(即数据)的方式。
state
并不全是复杂的,在一些场景中, state
可能规模非常小并且方便本地管理。例如从父组件A到子组件B直接透传数据是更简洁的。
但是,假设我们需要从组件A传递一些数据到外部组件J,该怎么办呢?
在这种情况下,管理状态的一种方式,可能是广播数据。然而,这种方式并不是最佳实践。
我们先前提到过,当应用变的越来越大,数据管理往往会更复杂。这种情况下往往会诞生一种需求,用中央仓库存储各种组件(甚至不是组件)的 state
,而不是用prop透传,毕竟prop透传会成为深度嵌套组件的麻烦。
基于以上原因,产生了对全局状态的需求,希望有一个可靠的中心数据源,能让所有程序中的组件都可以轻松访问任意一个状态,而且几乎没有任何限制。
何为Redux?
Redux 自从2015年发布以来,已经变成了最受欢迎的 React 应用开发的状态管理库。它是一个可控的状态容器,允许我们使用纯 JavaScript,并采用强制执行一致的模式,来确保我们的应用程序在客户端、服务器和本机环境中可靠,和易于测试。
除了 React , Redux 也可以用到其他JS框架和库里面,例如 Vue.js。
然而, Redux 近来也受到一些质疑,关于它使用起来有有一定门槛。出现这种负反馈,或许是因为,编写 actions
来定义每个状态的更改,然后创建多个 reducers
来控制这些 actions
可能会导致大量代码,并且这些代码很快就会变得难以管理。
为了解决这个问题,Facebook 和 React 核心团队成员,软件工程师 Dan Abramov 和 Andrew Clark 创造了 Redux 工具箱。它简化了存储设置和减少了必须的字段,使其成为高效 Redux 开发的首选工具。Redux 工具箱默认也遵循最佳实践。
Redux工作原理
在我们探究如何使用 Redux 在 React 应用中进行状态管理前,我们先来看一下 Redux 的工作原理。 典型的 Redux 设置由以下部分组成:
State
: 即应用中的数据,组件中的 state 更新时也会引发组件重新渲染。Reducers
: 它是 Redux 存储更新的媒介,reducer
接收一个action
,并根据action type
和payload
来操纵存储中的state
。Actions
: 通过UI组件触发的更新存储的函数;action
接受type
和payload
两个参数,它通过dispatcher
被触发。虽然type
参数定义了发送到reducer
的操作类型,但payload
才是reducer
在存储中更新的数据。
下面是redux.js.org上的一个图示,展示了在 Redux 状态管理库中的数据流。
React怎么用Redux管理状态?
我们来仔细研究一下如何使用 Redux 来管理 React 应用程序中的 state
。为了演示,我们将通过构建一个基本的计数器应用程序来简单的展示实现。
项目设置
用下面的命令创建一个 redux-demo
的项目:
然后,安装 redux
包(使我们能够在应用程序中使用 Redux)和另一个名为 react-redux
的包,这个包能够简化 React 应用连接到 Redux 存储和 reducers
:
安装依赖后启动:
由于我们专注于使用 Redux,因此我们不会详细介绍构建 React 组件的细节。
在 src
文件夹中,创建一个名为 Components
的新文件夹,然后创建两个名为 Counter.js
和 Counter.css
的文件。将以下代码添加到 Counter.js
文件中:
代码里有两个按钮,后面将使用它们来增加或减少计数器的值。
接下来,将 Counter.js
导入 App.js
。更新后的 App.js
如下所示:
设置Redux
在 src
文件夹中,创建名为 store
的文件夹;在此文件夹中创建 index.js
文件。我们还没有订阅 store
,因为我们只是设置计数器值;还没有准备好开始监听其状态的变化。
然后,将应用连接到 Redux store,以便应用的组件可以使用该 store;并导出 counterReducer
的实例。
src/store/index.js
文件现在应如下所示:
提供 store 并访问 store 里面的数据
为了让应用组件使用 store 作为中央状态存储库,我们需要从 react-redux
导入的 Provider
组件包装根 App
组件。然后,我们将通过将存储作为 prop
传递给 Provider
组件来引用该存储。
为此,请更新 src/index.js
文件,如下所示:
为了从 Counter
组件访问存储中的数据,我们将从 React-Redux
库中导入 useSelector
Hook。这个 Hook 将使能够让我们希望从 store 里获取想要的数据。useSelector
的另一个好处是它在幕后管理订阅。
我们使用 useSelector
Hook 从存储中提取计数器 state
。接下来,我们将传递一个函数,该函数接收 Redux 管理的 state
以及我们想要提取的 state
部分。最后,我们将输出计数器值,代码如下:
到目前为止,我们已经了解了如何检索 Redux 管理的数据。现在,我们看一下如何更新数据。
调度 actions 更新数据
为了将计数器值增加或减少 1,我们使用 react-redux
包中的 useDispatch
Hook。
首先,我们调用 useDispatch
,返回一个调度函数,我们可以调用该函数来针对 Redux 存储调度 action
。接下来,我们将创建各个按钮的事件函数,并且在函数里,我们将传递 type
。
更新后的 Counter.js
代码如下所示:
当单击递增或递减按钮时,会调用适当的 action
将计数器值增加或减少 1。
我们仔细研究了如何使用 Redux 来管理 React 应用程序中的 state
。现在,让我们看看如何使用 Vuex 来管理 Vue 应用程序中的 state
。
何为Vuex?
Vue 由 Evan You 创建,并由 Vue 核心团队维护。 Vuex 基于与 Redux 相同的 Flux 架构。 Vuex 是 Vue.js 应用的状态管理库。
通过这个库,应用程序 state
是集中的,应用中的每个组件都可以在任何时间点访问所需的 state
。使用 Vuex,能够很容易的获取和更新 state
。
Vuex工作原理
Vuex states
, getters
, mutations
, 和 actions
的集合:
States
: 就像Redux一样,state
定义了整个应用的全局数据属性;这使得定位特定数据变得容易,开发人员轻松获取当前应用程序状态的快照用于调试或其他目的。Getters
:store 中的计算值。在构建时,我们可能需要根据某个时间点计算派生状态,例如,过滤帖子列表并获取总量。如果该值将被多个组件使用,那么我们可以通过使用 getter 来实现这一目的。这将防止我们在不同的组件中重复实现相同作用的函数。Mutations
:提交mutation
是有效更新 Vuex 存储中状态的唯一方法。Mutations
像事件一样;每个mutation
都有一个字符串类型和一个处理函数;状态修改由mutation
处理函数执行。Actions
:其工作方式与mutation
非常相似,但是,操作不是直接改变state
,而是提交改变需要异步操作的state
的mutation
。
下面是vuex.vuejs.org上的一个图示,展示了在 Vuex 状态管理库中的数据流。
Vue.js怎么用Vuex管理状态?
为了展示如何使用 Vuex 来管理 Vue 应用程序中的状态,让我们从 Redux 演示中构建一个计数器应用的副本,具有相同的结构和功能。
项目设置和创建 Vuex store
首先使用以下命令创建 Vue 项目名称 vuex-demo
:
在 Vue 项目设置过程中,我们会被问到一系列问题。对于本教程,我们采用以下配置:
提示 | 选项 |
---|---|
Please pick a preset | Manually select features |
Check the features needed for your project | 默认选择 + Vuex |
Choose a version of Vue.js that you want to start the project with | 3.x |
Pick a linter / formatter config | ESLint with error prevention only |
Pick additional lint features | Lint on save |
Where would you prefer placing config for Babel, ESLint, etc. | In dedicated config files |
Save this as a preset for future projects? | N |
我们从创建项目的时候就很容易的将 Vuex 安装到应用中,可以到 src/store/index.js
找到它。
如果应用程序没有 Vuex,只需使用以下命令安装库:
注意,在上面的代码中添加 @next 会安装最新版本的 Vuex
继续,由于我们聚焦在使用 Vuex,因此我们将保持 Counter 组件简单。
在 src/Components
文件夹,创建一个名为 Counter.vue
的文件,并添加以下代码:
接下来,将 Counter.vue
导入到 App.vue
文件中。 App.vue
文件应如下所示:
接下来,我们需要为 demo 创建适当的 state
, mutations
, actions
和 getters
。
在 Vue.js 组件中使用 Vuex 存储
state
是存储中的一揽子属性。因此,为了定义计数器值的 state
,我们将其作为键值插入到存储中的 state
中。我们还给它初始值为0,如下所示:
要访问 Counter
组件中的计数器值,我们首先导入 store
,然后定位所需的 state
(在本例中为 Counter
):
为了使按钮更新计数器值,我们将在 Counter
组件中创建方法,并调度一个调用 mutation
(我们传递有效 payload
)的操作来更新 state
。它是从 Counter
组件传递的有效 payload
,用于更新计数器 state
(将其递减或递增 1)。
为了实现这一目标,我们将更新 Counter.vue
,如下所示:
接下来,更新 stote:
使用 getters 读取 state
假设我们想要读取 state
的值,并可能用它来执行外部操作。我们可以使用 getter
来实现这一点。
在计数器演示中,我们将读取计数器值并在 DOM 上渲染该值乘以 2。
让我们更新 store 以使用 getter
,如下所示:
我们现在可以从 App.vue
文件访问修改后的 CounterValue
。我们使用计算属性来实现这一点,如下所示:
调度更新数据的actions
在 Vue 中,最佳实践是仅在执行异步操作时使用 actions
。由于我们的演示不是异步的,因此我们可以参考 Vuex docs 来了解如何使用 actions
来分派数据,同时处理异步操作和处理 Promise,例如从 API 获取数据。
结论
Redux 和 Vuex 状态管理库在开发者生态系统中广泛使用。在本文中,我们探索了这两个库,展示了它们的工作原理,并演示了如何使用它们。我们还研究了 Redux 工具包,并展示了它如何帮助简化 Redux 设置、帮助避免常见错误,以及如何用名为 configureStore
的改进版本替换 createStore。
您可以在官方文档中阅读有关 Redux Toolkit 的更多信息。同样,您可以从其官方文档中了解有关 Vuex 的更多信息。
这些库可以充当所有应用程序状态的可预测中央存储,但最好避免将它们与不是很复杂的应用一起使用,因为这可能会让项目变得更加复杂和乏味。
与 Vuex 相比,Redux 是一个更流行、支持更好的库,但 Vuex 似乎是一个维护性更好的状态管理库。但是,选择权在您手中,具体取决于您的具体项目需求。
我希望本文能够帮助您更好地了解 Redux 和 Vuex 的工作原理,并为您提供有用的信息来确定哪种解决方案最适合您的项目。