Vuex 4 指南,使用 Vue3 的須要看看!

做者:Anthony Gore
譯者:前端小智
來源:vuejsdevelopers

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。前端

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。vue

Vuex 是 Vue.js 生態系統中必不可少的工具。可是新接觸 Vuex 的開發人員可能會被諸如「狀態管理模式」這樣的術語所排斥,而且對他們實際須要Vuex的目的感到困惑。git

本文算是 Vuex的入門,固然也會 Vuex 的高級概念,並向你們展現如何在應用程序中使用 Vuex。github

Vuex 解決的問題

要理解Vuex,首先要理解它要解決的問題。面試

假設咱們開發了一個多用戶聊天應用。界面有用戶列表、私人聊天窗口、帶有聊天記錄的收件箱和通知欄,通知用戶當前未查看的其餘用戶的未讀消息。vuex

數以百萬計的用戶天天經過咱們的應用與數以百萬計的其餘用戶聊天。然而,有人抱怨一個惱人的問題:通知欄偶爾會給出錯誤的通知。用戶被通知有一條新的未讀消息,但當他們查看時,它只是一條已經被看過的消息。npm

該做者所描述的是幾年前 Facebook 開發人員在其聊天系統中遇到的真實狀況。 解決這一問題的過程當中 開發人員建立名爲 "Flux"的應用程序體系結構。 Flux 構成了Vuex,Redux 和其它相似庫的基礎。設計模式

Flux

Facebook開發者爲「殭屍通知」這個問題,苦苦掙扎了一段時間。他們最終意識到,它的持久性不只僅是一個簡單的缺陷——它指出了應用程序架構中的一些潛在缺陷。數組

抽象中最容易理解該缺陷:當應用程序中有多個共享數據的組件時,它們互連的複雜性將增長到沒法預測或理解數據狀態的地步。 所以,該應用程序沒法擴展或維護。微信

Flux 是一個模式,不是一個庫。咱們不能去Github下載 Flux。它是一種相似MVC的設計模式。像Vuex和Redux這樣的庫實現Flux模式的方式與其餘框架實現MVC模式的方式相同。

事實上,Vuex並無實現Flux的所有,只是一個子集。不過如今不要擔憂這個問題,咱們關注於理解它所遵循的關鍵原則。

原則1:單一來源

組件可能具備僅須要瞭解的本地數據。 例如,滾動條在用戶列表組件中的位置可能與其餘組件無關。

可是,要在組件之間共享的任何數據(即應用程序數據)都必須保存在一個單獨的位置,與使用它的組件分開。

這個單一位置稱爲 "store"。 組件必須從該位置讀取應用程序數據,而且不能保留其本身的副本以防止衝突或分歧。

import { createStore } from "vuex";

// Instantiate our Vuex store
const store = createStore({

  // "State" 組件的應用程序數據
  
  state () {
    return {
      myValue: 0
    };
  }
});

// 組件從其計算的屬性訪問 state 
const MyComponent = {   
  template: "<div>{{ myValue }}</div>",
  computed: {
    myValue () {
      return store.state.myValue;
    }   
  } 
};

原則2:數據是隻讀的

組件能夠從store中自由讀取數據。 可是不能更改 store 中的數據,至少不能直接更改。

取而代之的是,它們必須告知 store 要更改數據的意圖,store由負責經過一組定義的功能(稱爲mutation)進行更改。

爲何採用這種方法? 若是咱們集中數據更改邏輯,那麼在狀態不一致的狀況下,咱們只須要在同一地方排查就好了,不用到具體的每一個文件中。 咱們將某些隨機組件(可能在第三方模塊中)以意外方式更改數據的可能性降至最低。

const store = createStore({ 
  state() { 
    return {
      myValue: 0
    };
  }, 
  mutations: { 
    increment (state, value) { 
      state.myValue += value;
    }
  } 
});
// 須要更新值嗎?
// 錯誤的,不要直接更改 store 值
store.myValue += 10;
// 正確的,調用正確的 mutations。
store.commit('increment', 10);

原則3:mutation 是同步的

若是應用程序在其體系結構中實現了上述兩個原則,那麼調試數據不一致就容易得多。能夠記錄提交併觀察狀態如何變化(在使用Vue Devtools 時確實能夠這樣作)。

但若是咱們的mutation被異步調用,這種能力就會被削弱。咱們知道提交的順序,但咱們不知道組件提交它們的順序。

同步mutation可確保狀態不取決於不可預測事件的順序和時間。

太酷了,那麼 Vuex 究竟是什麼?

有了全部這些背景知識,咱們終於能夠解決這個問題-Vuex 是一個庫,可幫助咱們在Vue應用程序中實現Flux架構。 經過執行上述原則,即便在多個組件之間共享數據時,Vuex 仍可將咱們的應用程序數據保持在透明且可預測的狀態。

如今,咱們已經對Vuex有了一個高級的瞭解,咱們看看如何在實際項目建立基於Vuex的應用程序。

作一個使用 Vuex to-do-list

爲了演示Vuex的用法,咱們設置一個簡單的待辦應用程序。 你們能夠在此處訪問代碼的有效示例。

示例地址:https://codesandbox.io/s/happ...

若是你們本身的電腦嘗試一波,那麼可使用下面的命令:

vue create vuex-example

安裝 Vuex

cd vuex-example
npm i -S vuex@4
npm run serve

建立一個 Vuex store

如今,建立 Vuex store,在項目中建立 src/store/index.js

mkdir src/store
touch src/store/index.js

打開文件並導入createStore方法。此方法用於定義store及其特性。如今,咱們導出該store ,以便在Vue應用中能訪問它。

// src/store/index.js

import { createStore } from "vuex";

export default createStore({});

將 store 添加到 Vue 實例

爲了能夠從任何組件中訪問 Vuex store,咱們須要在主文件中導入 store 模塊,並將store做爲插件安裝在主Vue實例上

// src/main.js

import { createApp } from "vue";
import App from "@/App";
import store from "@/store";

const app = createApp(App);

app.use(store);

app.mount("#app");

建立一個簡單的應用程序

如上所述,Vuex 的重點是一般在大型應用程序中建立可擴展的全局狀態。 可是,咱們能夠在一個簡單的待辦應用程序中演示其功能。

完成後效果以下所示:

image.png

如今,刪除 HelloWorld 文件:

rm src/components/HelloWorld.vue

TodoNew.vue

如今,添加一個新組件 TodoNew,它負責建立新的待辦事項。

touch src/components/TodoNew.vue

打開 TodoNew.vue 並輸入如下內容:

// src/components/TodoNew.vue

<template>
  <form @submit.prevent="addTodo">
    <input
      type="text"
      placeholder="Enter a new task"
      v-model="task"
    />
  </form>
</template>

如今轉到組件定義,有兩個局部狀態屬性-task和給新待辦事項提供惟一標識符的id

// src/components/TodoNew.vue

<template>...</template>
<script>
export default {
  data() {
    return {
      task: "",
      id: 0
    };
  },
  methods: {
    addTodo: function() {
      //
    }
  }
};
</script>

定義 store 狀態

過會,咱們會建立一個顯示待辦事項的組件。 因爲它和TodoNew組件都須要訪問相同的數據,所以這是咱們在 Vuex 存儲中保存的全局state 的理想選擇。

如今,回到state並定義屬性狀態。 這裏使用 Vux4 提供的 createStore 函數,該函數返回一個對象。 該對象具備一個屬性 todos,它是一個空數組。

// src/store/index.js
import { createStore } from "vuex";

export default createStore({
  state () {
    return {
      todos: []
    }
  }
});

定義 mutation

從原則2能夠知道,Vuex state 不能直接更改,須要定義mutator函數。

如今,咱們向store添加一個mutation屬性,並添加一個函數屬性addTodo。 全部mutator方法第一個參數。 第二個可選參數是 store,第二個是傳遞的數據。

// src/store/index.js

import { createStore } from "vuex";

export default createStore({
  state () {
    return {
      todos: []
    }
  },
  mutations: {
    addTodo (state, item) {
      state.todos.unshift(item);
    }
  }
});

使用 commit 調用 mutation

如今,能夠在TodoNew組件中使用它,在 TodoNew組件定義一個addTodo方法。

要訪問store ,咱們可使用全局屬性this.$store。 使用commit方法建立一個新的mutation。 須要傳遞了兩個參數-首先是mutation的名稱,其次是咱們要傳遞的對象,是一個新的待辦事項(由idtask值組成)。

// src/components/TodoNew.vue
methods: {
  addTodo: function() {
    const { id, task } = this;
    this.$store.commit("addTodo", { id, task });
    this.id++;
    this.task = "";
  }
}

回顧

到目前爲止:

  1. 用戶將待辦事項經過輸入框輸入,並綁定到 task 變量。
  2. 提交表單後,將調用addTodo方法
  3. 建立一個待辦事項對象並將其「提交」到store中。
// src/components/TodoNew.vue
<template>
  <form @submit.prevent="addTodo">
    <input
      type="text"
      placeholder="Enter a new task"
      v-model="task"
    />
  </form>
</template>
<script>
export default {
  data() {
    return {
      task: "",
      id: 0
    };
  },
  methods: {
    addTodo: function() {
      const { id, task } = this;
      this.$store.commit("addTodo", { id, task });
      this.id++;
      this.task = "";
    }
  }
};
</script>

讀取 store 數據

如今,咱們已經建立了用於添加待辦事項的功能。 接下來,就是把它們顯示出來。

建立一個新組件TodoList.vue 文件。

touch src/components/TodoList.vue

內容以下:

// src/components/TodoList.vue
<template>
<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.description }}
  </li>
</ul>
</template>

todos是一個計算屬性,咱們在其中返回Vuex store 的內容。

// src/components/TodoList.vue

<script>
export default {
  computed: {
    todos() {
      // 
    }
  }
};
</script>

定義 getters

與直接訪問store 內容不一樣,getter是相似於存儲的計算屬性的函數。在將數據返回到應用程序以前,這些工具很是適合過濾或轉換數據。

例如,下面有getTodos,它返回未過濾的狀態。 在許多狀況下,可使用filtermap來轉換此內容。

todoCount返回todo數組的長度。

經過確保組件願意保留數據的本地副本,getter有助於實現原則1,即單一數據來源。

// src/store/index.js

export default createStore({
  ...
  getters: {
    getTodos (state) {
      return state.todos;
    },
    todoCount (state) {
      return state.todos.length;
    }
  }
})

返回TodoList組件,咱們經過返回this.$store.getters.getTodos來完成功能。

// src/components/TodoList.vue

<script>
export default {
  computed: {
    todos() {
      return this.$store.getters.getTodos;
    }
  }
};
</script>

App.vue

要完成此應用程序,如今要作的就是導入並在App.vue中聲明咱們的組件。

// src/App.vue

<template>
  <div>
    <h1>To-Do List</h1>
    <div>
      <TodoNew />
      <TodoList />
    </div>
  </div>
</template>
<script>
import TodoNew from "@/components/TodoNew.vue";
import TodoList from "@/components/TodoList.vue";

export default {
  components: {
    TodoNew,
    TodoList
  }
};
</script>

你真的須要Vuex嗎?

顯然,在大型應用程序中,擁有全局狀態管理解決方案將有助於讓咱們的應用程序可預測和可維護。

但對於比較小的項目,有時候以爲使用 Vuex 太大材小用了,還這個仍是你們跟着實際需求走比較合理。

Vuex的優勢:

  • 易於管理全局狀態
  • 強大的調試全局狀態

Vuex的缺點:

  • 額外的項目依賴
  • 繁瑣的模板

~ 完, 我是刷碗智,刷碗去咯,下期見!


原文:https://vuejsdevelopers.com/2...

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

交流

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。

相關文章
相關標籤/搜索