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

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

使用狀態(tài)樹(shù)

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

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

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

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

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

普通方式

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

首先,只需將狀態(tài)導(dǎo)出為 函數(shù),將變量和操作作為 store/index.js 中的對(duì)象導(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>
模塊方法也適用于頂級(jí)定義,而無(wú)需在 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來(lái)維護(hù)state,getters,actions和mutations,同時(shí)具有單個(gè)單獨(dú)的操作文件,那么仍然可以正確識(shí)別該文件。

注意:在使用拆分文件模塊時(shí),必須記住使用箭頭函數(shù)功能, this 在詞法上可用。詞法范圍this意味著它總是指向引用箭頭函數(shù)的所有者。如果未包含箭頭函數(shù),那么this將是未定義的(undefined)。解決方案是使用 "normal" 功能,該功能會(huì)將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 方法會(huì)在渲染頁(yè)面前被調(diào)用,作用是填充狀態(tài)樹(shù) (store) 數(shù)據(jù),與 asyncData 方法類(lèi)似,不同的是它不會(huì)設(shè)置組件的數(shù)據(jù)。

關(guān)于 fetch 方法的更多信息,請(qǐng)參考 頁(yè)面 fetch 方法API。

nuxtServerInit 方法

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

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

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

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

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

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

Vuex 嚴(yán)格模式

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

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)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)