使用操作(Actions)进行异步状态更改

Vuex 中的操作(Actions)是处理 store 异步逻辑的主要方式。突变必须是同步的,但如果选择的话,操作也可以是异步的。另一个区别是操作获取代表存储本身的上下文对象。这允许操作调用突变(mutations)或直接与状态(state)一起工作。一般来说,大多数开发人员都会从他们的操作(actions)中调用突变(mutations)。

这可能看起来有点令人困惑,但一般来说,将操作(actions)视为对 store 的异步支持。一旦我们看到一两个例子就会明白。

让我们看一个示例操作(action)。以下代码片段包含一个突变和一个将利用该突变的异步操作:

mutations: {
    setBooks(state, books) {
        state.books = books;
    }
},
actions: {
    loadBooks(context) {
        fetch('/data/books.json')
        .then(res => res.json())
        .then(res => {
            context.commit('setBooks', res);
        });
    }
},

查看 loadBooks,您可以看到它发出网络请求,完成后,它会调用前面的突变并让它存储结果数据。

调用动作(action)与突变略有不同;您可以使用调度(dispatch)来代替提交(commit)调用:

this.$store.dispatch('loadBooks');

与突变一样,操作(actions)可以将传递给操作方法的参数作为第二个参数。接下来,您将构建一个 action 的示例。

练习 9.05:使用异步逻辑的操作(actions)

在本练习中,您将构建一个需要异步逻辑才能完成的操作(action)示例。这与许多现实场景非常相似,其中应用程序所需的数据是在远程 API 上找到的。您将实现网络调用并在 Vuex 存储中使用结果。

在此示例中,您将在 public 文件夹中名为 data 的子目录下设置一个可用的 JSON 资源。 当 Vue 构建代码时,它会将 public 文件夹中的所有内容复制到应用程序,使其在运行时可用。JSON 文件包含四本书的数组。每本书都有类型(type)、标题(title)和页数(number of pages)。

要访问本练习的代码文件,请参阅 https://packt.live/3eE6KQd

  1. 虽然不是必需的,但这就是 JSON 数据的结构。随意构建您自己的:

    [
        {
            "type": "nonfiction",
            "title": "Truth about Cats",
            "pages": 200
        },
        {
            "type": "nonfiction",
            "title": "Truth about Dogs",
            "pages": 100
        },
        {
            "type": "fiction",
            "title": "The Cat Said Meow",
            "pages": 400
        },
        {
            "type": "fiction",
            "title": "The Last Dog",
            "pages": 600
        }
    ]
  2. 在新 store(位于 store/index.js 的常用位置)中,设置一个 books 空数组,然后定义一个操作,该操作将使用 Fetch API 检索 JSON 内容。(您将在第 10 章 “使用 Vuex - 获取远程数据” 中看到更多使用 API 的示例,以及 Axios 库形式的更强大的 HTTP 方式。)检索数据时,然后调用一个突变(mutation)来存储结果:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
        state: {
            books:[]
        },
        mutations: {
            setBooks(state, books) {
                state.books = books;
            }
        },
        actions: {
            loadBooks(context) {
            fetch('/data/books.json')
            .then(res => res.json())
            .then(res => {
                context.commit('setBooks', res);
            });
            }
        }
    })
  3. 为了调用此操作(action),请在组件中添加调度(dispatch)调用来运行操作(actions),然后添加代码来显示 books:

    <template>
        <div id="app">
            Books
            <ul>
                <li v-for="book in $store.state.books" :key="book.title">
                {{ book.title }}</li>
            </ul>
        </div>
    </template>
    
    <script>
    export default {
        name: 'app',
        created() {
            this.$store.dispatch('loadBooks');
        }
    }
    </script>

在图 9.6 中,您可以看到异步操作(action)请求其数据的结果:

image 2023 10 16 22 08 38 814
Figure 1. Figure 9.6: An example of data loaded asynchronously

现在您已经看到了在 Vuex 存储中使用异步操作的示例。请注意,即使您的代码是同步的,您也可以使用操作(actions)。如果您不确定数据将来是否会异步,那么这通常是一个好主意。现在让我们看一下简化一些样板 Vuex 语法的好方法。