开始在 Vuex 中存储 Vue 数据

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()– 访问所有突变,我们还需要添加我们的命名空间。要使用在 中调用的突变addUseruserStore我们会写this.$store.commit('users/addUser', {}).

结论#

我希望你喜欢这个 Vuex 入门指南。我们已经涵盖了加载、保存和持久化 Vuex 存储数据所需的一切。让我们回顾一下我们在这里看到的内容:

  • 我们创建了一个新的 Vuex 商店。
  • 我们已经学习了如何创建 getter 方法来获取 Vuex 数据。
  • 我们已经学习了如何使用突变并用commit(), 调用它们来更改 Vuex 数据。
  • 我们已经学习了如何使用模块来分离不同的数据存储。
  • 我们已经谈到了动作是异步的,而突变是同步的。
  • 我们已经学习了如何使用 localStorage 持久化我们的 Vuex 数据。

如果您想了解更多 Vuex 的实际应用,请阅读我们在 Vue 中创建待办事项列表应用程序的完整指南。更多 Vue 内容,都可以在这里找到