Vuex 是一个状态管理库,可让我们处理并最终存储来自 UI 的数据。在本文中,我们将向您介绍有关 Vuex 的概念、如何使用它以及如何使用它在本地存储数据。
什么是 Vuex?#
您可能熟悉状态的概念,这只是一种花哨的数据表达方式。我们可以将状态存储在data()
函数本身的 Vue 中。例如,在下面的 Vue 组件中,我们将切换状态存储为 false,并且每当我们button
在模板部分单击我们时,我们将其设置为 true:
<template>
<button id="myButton" @click="runToggle">My Button</button>
</template>
<script>
export default {
data() {
return {
toggleState: false
}
},
methods: {
runToggle: function() {
this.toggleState = true;
}
}
}
</script>
这对于交互很少的组件非常有用,但是如果我们有很多不同的组件,我们就会开始遇到问题,所有组件都依赖于相同的数据,可能跨越多个页面。为了处理这些数据,我们可以使用Vuex,它集中管理我们所有的数据,因此我们可以轻松地操作和访问它。
为什么要使用 Vuex?
使用 Vuex 的主要原因是当你的数据结构变得如此复杂时,在你的组件之间维护和发送它变得很麻烦。Vuex 提供了一个单一的点来存储、操作和获取你的数据——极大地简化了这个过程。对于较小的项目或小型独立组件,您不一定需要使用 Vuex!
Vuex 入门#
要开始使用 Vuex,我们首先需要一个有效的 Vue 项目。如果您是 Vue 的新手,请阅读我们的创建您的第一个 Vue 项目的指南。之后,在您的 Vue 项目文件夹中,通过运行以下命令安装 vuex:
npm i vuex
现在已经安装了 Vuex,我们可以开始在我们的项目中添加它。首先,我们将创建一个中央 Vuex 存储。
在我们的 Vue 项目中,我们有一个名为src/main.js
. 让我们在那里添加我们的商店。您可以将 main.js 文件更新为如下所示:
import { createApp } from 'vue'
import { createStore } from 'vuex'
import App from './App.vue'
// I'm also using a router
import router from './router'
const app = createApp(App);
// Create a store for our to do list items
const store = createStore({
state() {
},
getters: {
},
mutations: {
}
});
// We can chain use() functions, so our app is now using a router and our Vuex store
app.use(router).use(store).mount('#app')
Vuex 商店很容易配置,并且由于我们use(store)
在初始化我们的应用程序时使用过,它可以立即在我们应用程序的任何地方可用。让我们看看我们商店中的每个对象的作用:
- state() – 这是我们将存储数据(也称为状态)的地方。对我们数据的任何更新或更改都将反映在此
state()
功能中。 - getters – 这完全符合您的想法 – 它让我们可以从我们的商店获取数据。
- 突变– 这些是我们将用来更新数据的函数。我们可以在其中添加方法来随意更新和更改状态数据。
Vuex 中的state()和getter()#
如前所述,state()将存储我们的数据,getter是从我们的状态存储中获取数据的方法
让我们看一个商店的例子。下面,我有一个状态存储,它返回一个名为 的对象users
,它是一个不同的数组。我在这里放了一个作为示例,但是如果您愿意,可以将其留空。
const store = createStore({
state () {
return {
users: [
{ id: '123-123-123', name: 'John Doe', email: 'johndoe@fjolt.com' }
]
}
},
getters: {
users (state) {
// state variable contains our state data
return state.users;
}
}
mutations: {
}
});
我们state()
中的数据可以通过getters
. 我创建了一个 getter 函数,称为users
. 当调用它时,我们通过state
变量访问用户列表,该变量包含我们状态存储中的所有数据。因此,当我们返回时state.users
,我们会在我们的状态存储中获取所有用户。
使用 Vuex 修改或更改数据#
所以现在我们有一个存储一些数据的存储,以及一种通过 getter 函数获取这些数据的方法。要拥有一个成熟的商店,我们需要做的最后一件事是创建一个mutation
方法。这些方法允许我们更改state()
存储中的数据。
mutations: {
addUser(state, newUser) {
if(newUser.id !== undefined && typeof newUser.name == 'string' && typeof newUser.email == 'string') {
state.users.push({
id: newUser.id,
name: newUser.name,
email: newUser.email
})
}
}
}
当我们创建一个类似的新方法时addUser
,我们创建了两个参数——一个是状态,它是对状态存储的引用,另一个是我们使用这个突变推送的数据。上面的函数让我们像{ id: 'some-id', name: 'Jane Doe', email: 'janedoe@fjolt.com' }
通过这个突变一样推送一个对象,并将该值推送到 Vuex 存储。
突变是同步的
请注意,所有突变都是同步的。如果要使用异步事件,则必须使用操作。所以不要尝试调用 API 或在突变中返回承诺!
关于行动的简短说明
如果您需要返回一个承诺,或者在您的变更中使用异步事件,您不能使用变更。相反,使用操作。动作与突变基本相同,因为它们让我们改变我们的状态存储,但它们返回一个承诺并且可以是异步的。可以在 actions 属性中将操作添加到我们的 Vuex 存储中:
const store = createStore({
state () {},
getters: {}
mutations: {},
actions: {
waitASecond: function() {
setTimeout(() => {
// Do something here with state()
}, 1000)
}
}
});
由于动作可以是异步的,我们可以将它们用于各种异步事件,如 API 调用。所以请记住:同步事件的突变和异步事件的动作。
如何使用 Vuex Mutations 和 Getters#
现在我们已经定义了一个 getter 和一个 mutation,我们需要在我们的应用程序中使用它们。这些功能可以通过this.$store
. 由于我们已经在 main.js 中初始化了 Vuex 存储,所以在这个阶段我们真的不需要做任何其他事情。
让我们创建一个利用我们商店的简单组件。它所做的只是向商店添加一个新项目,然后控制台将所有项目记录为字符串化 JSON:
<template>
<div id="new-user">
<input type="text" placeholder="Add a username.." id="username" ref="username">
<input type="text" placeholder="Add an email.." id="email" ref="email">
<input type="submit" id="submit-user" @click="newUser" value="Submit">
</div>
</template>
<script>
// I am using uuid for the ID for each user
import { v4 as uuidv4 } from 'uuid'
export default {
name: "NewUser",
methods: {
newUser: function() {
// We use "commit" to call mutations in Vuex
this.$store.commit('addUser', {
id: uuidv4(),
name: this.$refs.username.value,
email: this.$refs.email.value
})
// We can access getters via this.$store.getters
let allUsers = JSON.stringify(this.$store.getters.users);
console.log('New User Added!')
console.log(`All Users are here: ${allUsers}`);
}
}
}
</script>
我们可以通过 访问我们商店中的几乎任何东西this.$store
。当用户在我们的模板中点击提交时,我们称之为突变。你可能会注意到我们已经写了:
this.$store.commit('addUser', {});
那是因为我们不直接用 Vuex 调用突变。相反,我们用commit()
它们来称呼它们。由于我们之前的突变被称为addUser
,我们可以使用 调用该突变this.$store.commit('addUser', {})
,其中第二个对象是我们传递给我们的突变的数据。
然后我们可以将我们所有的数据提交给我们的变异,它随后会更新我们在 Vuex 中的状态存储。现在我们可以轻松地将用户添加到我们的状态存储中,并可以从 Vue 应用程序中的任何组件访问它。
使用动作
注意:我们前面提到了异步事件的操作。你可以像突变一样使用动作,只是你必须调用this.$store.dispatch('actonName', {})
,其中第一个参数是你想要调用的动作,第二个是你传递给它的数据。
使用吸气剂
我们还使用我们的 getter 在添加用户时对所有用户进行控制台记录。要从 Vuex 访问任何 getter,您只需使用this.$store.getters
. 所有 getter 都将存储在该对象上,因此请从之前this.$store.getters.users
引用我们的users()
getter。
如何将 Vuex 数据保存到本地存储#
现在我们已经建立了我们的 Vuex store,我们可以根据需要操作或更改我们的 store。Vuex 的(也许令人惊讶的)事情是它不是持久的。这意味着当您刷新页面时,所有数据都会消失。解决此问题的一种方法是将数据保存到数据库中。另一个确保应用程序也可以离线工作的方法是使用localStorage
.
因此,我们将研究如何将 Vuex 数据保存到 localStorage,以便在刷新后保持不变。您也可以使用 API 将其保存到数据库中,这将允许用户在登录后访问他们的数据。
我们要做的第一件事是使用subscribe
我们商店的方法。回到main.js
您可以将其添加到文件末尾:
store.subscribe((mutation, state) => {
// The code inside the curly brackets fires any time a mutation occurs.
// When a mutation occurs, we'll stringify our entire state object - which
// contains our todo list. We'll put it in the users localStorage, so that
// their data will persist even if they refresh the page.
localStorage.setItem('store', JSON.stringify(state));
})
subscribe()
在 Vuex 中,只要我们的 store 发生突变就会触发 – 这意味着任何时候添加或删除数据,订阅事件都会触发。
这个订阅事件会将我们当前拥有的所有状态数据存储在一个localStorage
名为的项目中store
——这意味着整个 Vuex 存储将被保存到用户的本地计算机。
维护与 Vue 应用程序的 localStorage 链接
将其保存到 localStorage 是一回事,但在应用程序中显示它是另一回事。为此,我们需要在我们的 Vuex 突变中创建一个新的突变,如果它存在的话,它将state()
用我们的数据替换整个 Vuex 存储localStorage
:
mutations: {
loadStore() {
if(localStorage.getItem('store')) {
try {
this.replaceState(JSON.parse(localStorage.getItem('store')));
}
catch(e) {
console.log('Could not initialize store', e);
}
}
}
// ... other mutations
}
这个函数所做的就是检查localStorage
项目 ,store
是否存在,如果存在,我们使用replaceState()
– 一个用任何东西替换整个状态存储的函数 – 用这个 localStorage 数据替换它。
因为我们想在应用程序加载时运行它,所以我们需要将它添加到文件的beforeCreate()
钩子中App.vue
。
<script>
import { useStore } from 'vuex'
export default {
beforeCreate() {
// Get our store
const store = useStore()
// use store.commit to run any mutation. Below we are running the loadStore mutation
store.commit('loadStore');
}
}
</script>
同样,请记住,我们使用commit()
. 我们创建了一个名为 的变量store
,因为它不会在beforeCreate()
钩子中完全设置。使用它,我们启动我们的loadStore
突变,同步我们的 localStorage 和 Vuex 存储。
在 Vuex 中使用模块#
由于我们上面的数据存储非常简单,我们没有必要用模块来复杂化它。但是,有时您会拥有不想混合的单独数据。对于这类事情,我们可以使用模块,它本质上将我们的数据分离到不同的命名空间中,这样我们就可以单独获取、变异和存储它们。
模块遵循与之前相同的原则,唯一的区别是我们可以定义多个 Vuex 存储:
const userStore = {
namespaced: true,
state() {
return {
users: []
}
},
mutations: { // ... }
getters: { // ... }
}
const articleStore = {
namespaced: true,
state() {
return {
articles: []
}
},
mutations: { // ... }
getters: { // ... }
}
const store = createStore({
modules: {
users: userStore,
articles: articleStore
}
})
现在我们有两个逻辑上不同的数据存储。如果我们想访问userStores
,我们会在 上找到它this.$store
,因为它仍然包含我们所有的合并商店。
访问模块获取器
在上面的例子中,由于我们存储数据的方式略有不同,我们需要使用this.$store.getters['user/users']
getter 来访问我们的用户。如果我们有一个名为 的getter usernames
,我们同样可以通过使用来访问它this.$store.getters['users/usernames']
。
访问模块突变
与之前类似,我们仍然可以通过this.$store.commit()
– 访问所有突变,我们还需要添加我们的命名空间。要使用在 中调用的突变addUser
,userStore
我们会写this.$store.commit('users/addUser', {})
.
结论#
我希望你喜欢这个 Vuex 入门指南。我们已经涵盖了加载、保存和持久化 Vuex 存储数据所需的一切。让我们回顾一下我们在这里看到的内容:
- 我们创建了一个新的 Vuex 商店。
- 我们已经学习了如何创建 getter 方法来获取 Vuex 数据。
- 我们已经学习了如何使用突变并用
commit()
, 调用它们来更改 Vuex 数据。 - 我们已经学习了如何使用模块来分离不同的数据存储。
- 我们已经谈到了动作是异步的,而突变是同步的。
- 我们已经学习了如何使用 localStorage 持久化我们的 Vuex 数据。
如果您想了解更多 Vuex 的实际应用,请阅读我们在 Vue 中创建待办事项列表应用程序的完整指南。更多 Vue 内容,都可以在这里找到。