vuex практика vue

внешний интерфейс Vue.js Promise Vuex

Vue практика 05 vuex

геттерный метод

Иногда нам нужно получить какое-то состояние из состояния в хранилище, например фильтрация и подсчет списка:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

Если несколько компонентов должны использовать это свойство, мы либо дублируем функцию, либо извлекаем ее в общую функцию и импортируем в несколько мест — ни один из способов не идеален.

Vuex позволяет нам определять «геттеры» (которые можно рассматривать как вычисляемые свойства хранилища) в хранилище. Как и вычисляемые свойства, возвращаемое значение метода получения кэшируется на основе его зависимостей и пересчитывается только при изменении его зависимостей.

  1. Getter принимает состояние в качестве своего первого параметра:
const store = new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        add(state) {
            state.count++;
        },
        reduce(state) {
            state.count--;
        }
    },
    getters: {
        countAdd100: state => {
            return state.count + 100
        }
    }
})
  1. Внедрение геттеров в компоненты

import { mapState, getters } from "vuex";
3. Доступ к геттерам в компоненте

computed: {
    countAdd1001() {
      return this.$store.getters.countAdd100;
    }
  }
  1. Вспомогательная функция mapGetters
    Вспомогательная функция mapGetters просто сопоставляет геттеры в хранилище с локальными вычисляемыми свойствами, требуя, чтобы локальные вычисляемые свойства совпадали с именами методов, определенных в геттере, подобно массиву mapState.
 computed: {
    ...mapGetters([
      "countAdd100"
    ])
  }
  1. весь код
  • Код count.vue выглядит следующим образом:
<template>
    <div>
        <h2>{{msg}}</h2>
        <hr/>
        <!--<h3>{{$store.state.count}}</h3>-->
        <h6>{{countAdd100}}</h6>
        <h6>{{countAdd1001}}</h6>
        <div>
    <button @click="$store.commit('add')">+</button>
    <button @click="$store.commit('reduce')">-</button>
</div>
    </div>
</template>
<script>
import store from "@/vuex/store";
import { mapState, getters, mapGetters } from "vuex";
export default {
  data() {
    return {
      msg: "Hello Vuex"
    };
  },
  computed: {
    ...mapGetters([
      "countAdd100"
    ]),
    countAdd1001() {
      return this.$store.getters.countAdd100;
    }
  },

  store
};
</script>
  • код store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        add(state) {
            state.count++;
        },
        reduce(state) {
            state.count--;
        }
    },
    getters: {
        countAdd100: state => {
            return state.count + 100
        }
    }
})

export default store

Метод мутации

  1. Единственный способ изменить состояние в хранилище Vuex — отправить мутацию. Мутации в Vuex очень похожи на события: каждая мутация имеет строковый тип события (тип) и функцию обратного вызова (обработчик). В этой функции обратного вызова мы фактически изменяем состояние, и она принимает состояние в качестве первого параметра:
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

Вы не можете напрямую вызвать обработчик мутации. Эта опция похожа на регистрацию событий: «Когда вызывается тип мутации триггера, эта функция вызывается». Чтобы разбудить обработчик мутации, вам необходимо позвонить в Shore.comMit Method.

store.commit('increment')
  1. Отправить полезную нагрузку В store.commit можно передать дополнительные параметры, а именно полезную нагрузку мутации:
mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10)
  1. В большинстве случаев полезной нагрузкой должен быть объект, который может содержать несколько полей и записывать мутации более читабельно:
<button @click="$store.commit('incrementObj',{amount:100})">+100</button>

<button @click="$store.commit({type:'incrementObj',amount:1000})">+1000</button>

Action

  1. определение действия
    Действие похоже на мутацию, разница в следующем:
  • Действия вызывают мутации, а не изменения состояния напрямую.
  • Действие может содержать произвольные асинхронные операции. в коде нижеincrementAsyncОн имитирует асинхронную операцию.
 actions: {
        addAction({ commit }) {
            commit("add")
        },
        reduceAction({ commit }) {
            commit("reduce")
        },
        incrementAsync({ commit }) {
            setTimeout(() => {
                commit('add')
            }, 1000)
        }
    }

Функция действий принимает метод и имеет одинаковые свойства и хранить экземпляр объекта контекста, поэтому вы можете позвонить в Context.comMit представить мутацию или приобретенное государством и получателями и контекстом. Contect. Когда мы представили после модулей, вы узнаете, почему объект контекста не хранит сам экземпляр.
Должна ли мутация выполнять это ограничение синхронно? Действие не обязывает! Мы можем выполнять асинхронные операции внутри действия:

incrementAsync({ commit }) {
            setTimeout(() => {
                commit('add')
            }, 1000)
        }
  1. метод отправки вызывает действие
    Вызвать действие в компоненте, код такой:
 methods: {
            increment(){
                this.$store.dispatch("addAction");
            },
            decrement() {
                this.$store.dispatch("reduceAction")
            },
            incrementAsync() {
                this.$store.dispatch("incrementAsync")
            }
        }
  1. Метод mapAactions вызывает действие
    Первая эталонная картаДействия,import { mapActions} from "vuex";Пример кода выглядит следующим образом:
  methods: {
    ...mapActions([
      'addAction', // 将 `this.increment()` 映射为 `this.$store.dispatch('addAction')`

      // `mapActions` 也支持载荷:
      'reduceAction' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('reduceAction')`
    ]),
    ...mapActions({
      asyncAdd: 'incrementAsync' // 将 `this.asyncAdd()` 映射为 `this.$store.dispatch('incrementAsync')`
    })
  }
  1. Комбинированное действие
    Действия обычно асинхронны, так как же узнать, что действие завершилось? Что еще более важно, как мы можем объединить несколько действий для обработки более сложных асинхронных процессов?
    Во-первых, нужно понимать, что store.dispatch может обрабатывать промис, возвращаемый обработчиком сработавшего действия, а store.dispatch по-прежнему возвращает промис:
    Определите действие следующим образом:
  mutations: {
        reduce(state) {
            state.count--;
        }
    },
    actions: {
        actionA({ commit }) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    commit('reduce')
                    resolve()
                }, 1000)
            })
        }
    }

Код в компоненте выглядит следующим образом:

 methods: {
            decrement() {
                this.$store.dispatch('actionA').then(() => {
                   console.log("先减1再加1")
                   this.incrementAsync()
                })
            },
            incrementAsync() {
                this.$store.dispatch("incrementAsync")
            }
        }

модуль модульная группа

Благодаря использованию единого дерева состояний все состояния приложения будут агрегированы в относительно большой объект. Когда приложение становится очень сложным, объект хранилища может сильно раздуться.

Чтобы решить вышеуказанные проблемы, Vuex позволяет нам разделить хранилище на модули. Каждый модуль имеет свое состояние, мутации, действия, геттеры и даже вложенные подмодули — разбитые таким же образом сверху вниз:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

Пространства имен

По умолчанию действия, мутации и геттеры внутри модулей регистрируются в глобальном пространстве имен — это позволяет нескольким модулям реагировать на одну и ту же мутацию или действие.

Если вы хотите, чтобы ваш модуль был более инкапсулированным и пригодным для повторного использования, вы можете сделать его модулем с пространством имен, добавив namespaced: true . Когда модуль регистрируется, все его геттеры, действия и мутации автоматически именуются в соответствии с путем, зарегистрированным модулем. Например:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模块内容(module assets)
      state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // 嵌套模块
      modules: {
        // 继承父模块的命名空间
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // 进一步嵌套命名空间
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

В приведенном выше примере и myPage, и сообщения являются подмодулями учетной записи, но для myPage не задано пространство имен, поэтому myPage наследует пространство имен учетной записи. posts задает пространство имен, поэтому при доступе к геттерам внутри сообщений необходимо добавить полный путь.

Фактический рабочий код выглядит следующим образом:

const moduleA = {
    namespaced: true,
    state: { count: 10 },
    mutations: {
        increment(state) {
            // 这里的 `state` 对象是模块的局部状态
            state.count++
        }
    },

    getters: {
        doubleCount(state) {
            return state.count * 2
        }
    },
    actions: {
        incrementIfOddOnRootSum({ state, commit, rootState }) {
            if ((state.count + rootState.count) % 2 === 1) {
                commit('increment')
            }
        }
    },
    getters: {
        sumWithRootCount(state, getters, rootState) {
            return state.count + rootState.count
        }
    }
}


---在父节点中添加module定义
    modules: {
        a: moduleA
    }

Доступ к определенному модулю в vue

 <button @click="$store.commit('a/increment')">double</button>
  <button @click="doubleCount">doubleCount</button>
  

определение метода методов:

    count() {
      return this.$store.state.a.count
    },
     doubleCount() {
      return this.$store.commit('a/increment')
    }

Ссылка на ссылку

официальная документация vuex

Блог технического учителя