Nuxt.js Vuex 狀態(tài)樹

2020-02-13 17:13 更新
對于每個大項(xiàng)目來說,使用狀態(tài)樹 (store) 管理狀態(tài) (state) 十分有必要。這就是為什么 Nuxt.js 內(nèi)核實(shí)現(xiàn)了 Vuex。

使用狀態(tài)樹

Nuxt.js 會嘗試找到應(yīng)用根目錄下的 store 目錄,如果該目錄存在,它將做以下的事情:

  1. 引用 vuex 模塊
  2. 將 vuex 模塊 加到 vendors 構(gòu)建配置中去
  3. 設(shè)置 Vue 根實(shí)例的 store 配置項(xiàng)

Nuxt.js 支持兩種使用 store 的方式,你可以擇一使用:

  • 模塊方式: store 目錄下的每個 .js 文件會被轉(zhuǎn)換成為狀態(tài)樹指定命名的子模塊 (當(dāng)然,index 是根模塊)
  • Classic(不建議使用): store/index.js返回創(chuàng)建Vuex.Store實(shí)例的方法。

無論使用那種模式,您的state的值應(yīng)該始終是function,為了避免返回引用類型,會導(dǎo)致多個實(shí)例相互影響。

普通方式

Nuxt.js允許您擁有一個 store 目錄,其中包含與模塊對應(yīng)的每個文件。

首先,只需將狀態(tài)導(dǎo)出為 函數(shù),將變量和操作作為 store/index.js 中的對象導(dǎo)出:

export const state = () => ({
  counter: 0
})

export const mutations = {
  increment (state) {
    state.counter++
  }
}

然后,您可以擁有 store/todos.js 文件:

export const state = () => ({
  list: []
})

export const mutations = {
  add (state, text) {
    state.list.push({
      text,
      done: false
    })
  },
  remove (state, { todo }) {
    state.list.splice(state.list.indexOf(todo), 1)
  },
  toggle (state, todo) {
    todo.done = !todo.done
  }
}

Vuex將如下創(chuàng)建:

new Vuex.Store({
  state: () => ({
    counter: 0
  }),
  mutations: {
    increment (state) {
      state.counter++
    }
  },
  modules: {
    todos: {
      namespaced: true,
      state: () => ({
        list: []
      }),
      mutations: {
        add (state, { text }) {
          state.list.push({
            text,
            done: false
          })
        },
        remove (state, { todo }) {
          state.list.splice(state.list.indexOf(todo), 1)
        },
        toggle (state, { todo }) {
          todo.done = !todo.done
        }
      }
    }
  }
})

在您的 pages/todos.vue 中,使用 todos 模塊:

<template>
  <ul>
    <li v-for="todo in todos">
      <input type="checkbox" :checked="todo.done" @change="toggle(todo)">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
    </li>
    <li><input placeholder="What needs to be done?" @keyup.enter="addTodo"></li>
  </ul>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  computed: {
    todos () {
      return this.$store.state.todos.list
    }
  },
  methods: {
    addTodo (e) {
      this.$store.commit('todos/add', e.target.value)
      e.target.value = ''
    },
    ...mapMutations({
      toggle: 'todos/toggle'
    })
  }
}
</script>

<style>
.done {
  text-decoration: line-through;
}
</style>
模塊方法也適用于頂級定義,而無需在 store 目錄中實(shí)現(xiàn)子目錄

示例:您創(chuàng)建文件 store/state.js 并添加以下內(nèi)容

export default () => ({
  counter: 0
})

相應(yīng)的可以在文件夾中添加 store/mutations.js

export default {
  increment (state) {
    state.counter++
  }
}

模塊文件

您可以將模塊文件分解為單獨(dú)的文件:state.js,actions.js,mutations.js和getters.js。如果您使用index.js來維護(hù)state,getters,actions和mutations,同時具有單個單獨(dú)的操作文件,那么仍然可以正確識別該文件。

注意:在使用拆分文件模塊時,必須記住使用箭頭函數(shù)功能, this 在詞法上可用。詞法范圍this意味著它總是指向引用箭頭函數(shù)的所有者。如果未包含箭頭函數(shù),那么this將是未定義的(undefined)。解決方案是使用 "normal" 功能,該功能會將this指向自己的作用域,因此可以使用。

插件

您可以將其他插件添加到store(在模塊模式下),將其放入store/index.js文件中:

import myPlugin from 'myPlugin'

export const plugins = [ myPlugin ]

export const state = () => ({
  counter: 0
})

export const mutations = {
  increment (state) {
    state.counter++
  }
}

有關(guān)插件的更多信息: Vuex 文檔.

fetch 方法

fetch 方法會在渲染頁面前被調(diào)用,作用是填充狀態(tài)樹 (store) 數(shù)據(jù),與 asyncData 方法類似,不同的是它不會設(shè)置組件的數(shù)據(jù)。

關(guān)于 fetch 方法的更多信息,請參考 頁面 fetch 方法API

nuxtServerInit 方法

如果在狀態(tài)樹中指定了 nuxtServerInit 方法,Nuxt.js 調(diào)用它的時候會將頁面的上下文對象作為第2個參數(shù)傳給它(服務(wù)端調(diào)用時才會醬紫喲)。當(dāng)我們想將服務(wù)端的一些數(shù)據(jù)傳到客戶端時,這個方法是灰常好用的。

舉個例子,假設(shè)我們服務(wù)端的會話狀態(tài)樹里可以通過 req.session.user 來訪問當(dāng)前登錄的用戶。將該登錄用戶信息傳給客戶端的狀態(tài)樹,我們只需更新 store/index.js 如下:

actions: {
  nuxtServerInit ({ commit }, { req }) {
    if (req.session.user) {
      commit('user', req.session.user)
    }
  }
}
如果你使用_狀態(tài)樹模塊化_的模式,只有主模塊(即 store/index.js)適用設(shè)置該方法(其他模塊設(shè)置了也不會被調(diào)用)。

這時context被賦予nuxtServerInit作為第二個參數(shù),它與asyncData或fetch方法相同。

nuxtServerInit 方法接收的上下文對象和 fetch 的一樣,但不包括 context.redirect() 和 context.error()。

注意:異步nuxtServerInit操作必須返回Promise來通知nuxt服務(wù)器等待它們。
actions: {
  async nuxtServerInit({ dispatch }) {
    await dispatch('core/load')
  }
}

Vuex 嚴(yán)格模式

默認(rèn)情況下,在開發(fā)模式下啟用嚴(yán)格模式,在生產(chǎn)模式下關(guān)閉模式。要在dev中禁用嚴(yán)格模式,請遵循以下示例。

Module Mode

export const strict = false

經(jīng)典模式

此功能已經(jīng)棄用,將在Nuxt 3中刪除。

要使用經(jīng)典模式創(chuàng)建Vuex,我們應(yīng)該創(chuàng)建store/index.js到處返回Vuex實(shí)例的方法的文件:

import Vuex from 'vuex'

const createStore = () => {
  return new Vuex.Store({
    strict: false,
    state: () => ({
      counter: 0
    }),
    mutations: {
      increment (state) {
        state.counter++
      }
    }
  })
}

export default createStore
我們不需要安裝,因?yàn)閂uex由Nuxt.js提供。

我們現(xiàn)在可以在我們的組件中使用this.$store:

<template>
  <button @click="$store.commit('increment')">{{ $store.state.counter }}</button>
</template>


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號