资讯专栏INFORMATION COLUMN

Vue_Vuex

animabear / 832人阅读

摘要:定义调用更改的中的状态的唯一方法是提交中的非常类似于事件每个都有一个字符串的事件类型和一个回调函数,参数。注意点必须是同步函数原因当触发的时候,回调函数还没有被调用。实质上任何在回调函数中进行的状态的改变都是不可追踪的。

Vuex

集中式状态管理

使用时机:
每一个组件都拥有当前应用状态的一部分,整个应用的状态是分散在各个角落的。然而经常会需要把把状态的一部分共享给多个组件。

Vuex:一个专门为Vue.js 应用设计的状态管理架构.

状态管理:统一管理和维护各个vue组件的可变化状态(可以理解成vue组件里的某些data数据,全局变量)

出现背景:

追踪自定义事件NaN,这个事件由那个组件触发的,谁在监听它。

业务逻辑遍布各个组件,导致各种意想不到的问题。

由于要显式的分发和监听,父组件和子组件强耦合

Vuex 核心概念:

状态树:包含所有应用层级状态。意味着,每个应用将仅仅包含一个store实例。单状态树能够直接定位任意特定的状态片段。

Getters:在Vue组件内部获取stroe中状态/数据的函数

Mutations:通过事件回调函数来修改store中的状态的变化.

Actions:在组件内部使用函数,分发mutations事件的函数.

为什么需要有action

每一个web应用都至少对应一个数据结构,而导致这个数据结构状态更新的来源很丰富;光是用户对view的操作(dom事件)就有几十种,此外还有ajax获取数据、路由/hash状态变化的记录和跟踪。

来源丰富不是最可怕的,更可怕的是每个来源提供的数据结构并不统一。DOM事件还好,前端可以自主控制与设计;ajax获取的数据,其结构常常是服务端开发人员说了算,面对业务场景跟前端并不相同,往往会为了自己的便利,给出在前端看来很随意的数据结构。

web应对中所有的数据与状态的变化,几乎都来自[事件],DOM事件,AJAX成功或失败事件,路由change事件,setTimeout定时器事件,以及自定义事件。任意时间都可能产生需要合并全局数据对象里的新数据或者线索。

是event响应函数里主动调用了action函数,并且传入它需要的数据。

action 作用:

action 是专门用来被component调用的函数

action函数能够通过分发相应的mutation函数, 来触发对stroe的更新

action 可以先从HTTP后端 或 store 中读取其它数据之后再分发更新事件

Vuex把状态分为:

组件本地状态

仅在一个组件内使用的状态(data字段)应用层级状态(应用级的状态不属于任何特定的组件,但每一个组件仍然可以监视其变化从而响应式的更新DOM)
组件内部使用的状态,通过配置选项传入Vue组件内部的意思。

应用级别状态

多个组件共用的状态
同时被多个组件共享的状态层级

简单使用

Vuex 应用的核心是store(仓库)理解成项目中使用的数据的集合。 包含着大部分的状态(即state)

Vuex和单纯的全局对象:

Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化。

不能截至改变store中的状态。改变store中的状态的唯一途径就是显示地分发 状态变更事件

作用:方便的跟踪每一个状态的变化。

vuex 把应用的数据和修改的数据的方法,放在了一个 sotre 对象里面统一管理,对数据的获取和操作则分别通过 vm新增的配置属性 vuexgettersactions 来进行

整个APP的数据就是存放在state对象里,随取随用.

定义一个mutations对象。可以把mutations理解为“用于改变state状态的一系列方法”

在vuex的概念里,state仅能通过mutations修改。
好处:能够更直观清晰的集中管理应用的状态。

数据流动是单向

组件可以调用actions

Actions是用来分发 mutations

只有mutations可以修改状态

store是反应式(状态的变化会在组件内部得到反映)

sotre只需要在最顶层的组件声明一次

在入口文件加入:

var store = new Vuex.Store({
    state: {
        a: false,
        money: 0    
    },
    mutations: {
        increment( state ) {
            store.state.a;
        }
    }
});

组件中使用:

computed: {
    a: function() {
        return store.state.a;
    }
}

使用Vuex遵守规则:

应用层级的状态应该几种到单个sotre对象中。

提交mutation是更改状态的唯一方法,并且这个过程是同步的。

异步逻辑都应该封装到action里面。

State

单一状态树

Vuex 使用 单一状态树。 使用一个对象包含全部的应用层级状态(数据)。把它作为一个唯一数据源提供方存在(全局变量)。
每个应用程序仅仅包含一个store实例。单状态数能够直接定位任意特定的状态片段,在调试过程中能够轻易的获取整个当前应用状态。(单状态树和模块化并不冲突)

Vuex 中数据都是单向的,Vue组件只能从 store获取。

如何在Vue组件中获得Vuex状态

由于 Vuex 的状态存储是响应式的,从 store 实例中 读取状态在计算属性computed 中返回某个状态。

    new Vue({
        el: ".app",
        computed: {
            count: function () {
                return stroe.state.count;
            }
        }
    });

store.state特性:

每当store.state.count变化的时候,都会重新求取计算属性,并且触发更新相关的DOM。

导致组件过度依赖全局状态单例。

每个模块化的组件中,需要频繁导入,并且在测试组件时需要模拟状态。

组件仍然保有局部状态

使用Vuex并不意味着需要将所有的状态放入Vuex。
优点:把所有状态放入Vuex会是的状态变化更显式和易调试。
缺点:代码变得冗长和不直观。

如果有些状态严格属于单个组件,最好还是作为组件的局部状态。

Getters

需要对数据进行第二次加工处理,全局函数处理,可以在 store中定义getters(可以认为store的计算属性)。

定义

const store = new Vue({
    state: {
        list: [{id: 1, text: "a"}, {id: 2, text: "b"}]
    },
    getters: {
        done: state => {
            return state.todos.filter(todo => todo.done);
        }    
    }
});

调用

store.getters.lenCount
Mutations

更改Vuex的store中的状态的唯一方法是提交 mutation.
Vuex中的mutations非常类似于事件:每个mutations都有一个字符串的 事件类型(type) 和 一个回调函数(handler),参数:state。

定义

const store = new Vue.store({
    state: {
        a: 0
    },
    mutations: {
        heade( state ) {
            state.a += 10;
        }
    }
});

调用

sotre.commit("heade");

传入多个参数(提交载荷Payload) 多数情况下,另外的参数,会是对象。

// 定义
mutations: {
    heade( state, n ) {
        state.a += n;
    }
}

// 调用
store.commit("heade", 100);

Mutations 需遵守 Vue 的响应规则

Vuex中的store中的状态是响应式的,变更状态时,监听状态的Vue组件也会自动更新。
注意:

最好提前在sotre中出初始化好所有所需属性。

当需要在对象上添加新属性时,应该使用Vue.set(obj, "newProp", 123) 或者 以新对象替换老对象。

使用常量替代Mutation事件类型

使用常量替代mutation事件类型在各种 Flux 实现中常见模式.
结果:可以使linter之类的工具发挥作用,同时把这些常量放在多带带的文件中可以让代码合作者对这个app包含的mutation清晰明了。

// mutation-types.js
export const FETCH_MOVIE_BY_ID = "FETCH_MOVIE_BY_ID";

// store.js
import Vuex form "vuex";
import {FETCH_MOVIE_BY_ID} from "./mutations-types.js";

const store = new Vuex.Store({
    state: {},
    mutations: {
        ["FETCH_MOVIE_BY_ID"]( state ) {
            // mutate state
        }
    }
});

mutation注意点:
mutation必须是同步函数
原因:当mutation触发的时候,回调函数还没有被调用。 实质上任何在回调函数中进行的状态的改变都是不可追踪的。

在组件中提交Mutations

定义:

increment: function( context ) {
    context.a += 10;
}

使用方式:

// 方式1
store.commit("increment"); // this.$store.commit("xxx")

// 方式2
methods: {
    mapMutations(["increment"]) // // 映射 this.increment() 为 this.$store.commit("increment")
}
Actions

Actions类似于mutations,不同点:

Actions 提交的是mutation,而不是直接变更状态。

Actinos 可以包含任意异步操作。

 store = new Vuex.Store({
    state: {
        a: 0
    },
    mutations: {
        add() {
            state.a += 10;
        }
    },
    actions: {
        add( context ) {
            context.commit("add");
        }
    }
});

Action 函数参数:store实例具有相同的方法和属性的context对象。
可以调用context.commit(); 执行一个mutation。 或者通过context.state 和 context.getters 来获取 state和 getters。

分发Action

Action通过store.dispatch方法触发.

store.dispatch();

Action 能够支持载荷方式和对象方式进行分发.

// 以载荷形式分发
store.dispatch("add", {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: "add",
  amount: 10
})

在组件中分发Action

定义:

increment: function( context ) {
    context.a += 10;
}

使用方式:

// 方式1
store.dispatch("increment"); // this.$store.dispatch("xxx")

// 方式2
methods: {
    mapActions(["increment"]) // // 映射 this.increment() 为 this.$store.commit("increment")
}

组合Actions

Action 通常是异步,如何知道action 什么时候结束。如何组合多个action,以处理更加复杂的异步流程?

store.dispatch的返回的是被处罚的action函数的返回值,因为,可以在action中返回Promise

actions: {
    actionA({commit}) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                commit("someMutation");
                resolve();
            }, 1000)
        })
    },
    actionB({dispatch}) {
        return dispatch("actionA").then(()=>{
            commit("someOhterMutation");
        })
    }
}

一个sotre.dispatch()在不同模块中可以出发多个action函数。在当前情况下,只有当所有触发函数完成后,返回的Promise才会执行。

案例:

import * as types from "../types";
import {fetchMoviesByType, fetchSearchMovies, fetchMovieById} from "../api";

const state = {
  movies: [],
  movieList: {
    title: "",
    total: 0,
    subjects: [],
  },
  busy: false,
  movie: {},
};

const actions = {
  [types.FETCH_MOVIES](context,payload){
    fetchMoviesByType(payload.type, payload.start, payload.count)
        .then(data=>{
          data.type = payload.type;
          return context.commit([types.FETCH_MOVIES], data)
        });
  },

  [types.FETCH_MOVIE_LIST](context,payload){
    fetchMoviesByType(payload.type, payload.start)
        .then(data=>context.commit([types.FETCH_MOVIE_LIST], data));
  },

  [types.FETCH_MOVIE_BY_ID](context, id){
    fetchMovieById(id)
        .then(data => context.commit([types.FETCH_MOVIE_BY_ID], data));
  },

  [types.SET_INFINITE_BUSY](context, data){
    context.commit([types.SET_INFINITE_BUSY], data);
  },

  [types.CLEAN_MOVIE](context){
    context.commit(types.CLEAN_MOVIE);
  },

  [types.CLEAN_MOVIES](context){
    context.commit([types.CLEAN_MOVIES])
  },

  [types.CLEAN_MOVIE_LIST](context){
    context.commit([types.CLEAN_MOVIE_LIST])
  }
};

const mutations = {
  [types.FETCH_MOVIES](state, list){
    state.movies.push(list);
  },

  [types.FETCH_MOVIE_LIST](state, list){
    state.movieList.title = list.title;
    state.movieList.total = list.total;
    state.movieList.subjects = state.movieList.subjects.concat(list.subjects);
    if(state.movieList.subjects.length < state.movieList.total){
      state.busy = false;
    }
  },

  [types.FETCH_MOVIE_BY_ID](state, movie){
    state.movie = movie;
  },

  [types.SET_INFINITE_BUSY](state, data){
    state.busy = data;
  },

  [types.CLEAN_MOVIE](state){
    state.movie = {};
  },

  [types.CLEAN_MOVIES](state){
    state.movies = [];
  },

  [types.CLEAN_MOVIE_LIST](state){
    state.movieList = {};
  }
};


export default {
  state,
  mutations,
  actions
}
`api.js` 发送ajax  // 定义ajax事件

`modules/movie.js` 中写 state,mutations,actions //  action 中执行ajax定义事件, 回调函数中执行mutations中定义的事件

`mutations` 定义事件, 第一个参数是`context`,当前定义的store

`types.js` 定义常量替代mutation事件类型
// src/components/header.vue
// 从vuex拿数据,然后渲染到页面上
// 如果需要修改可以调用setTitle
import { setTitle } from "../vuex/actions";

export default {
    vuex: {
        // 获取vuex状态数据
        getters: {
            title: state => state.title,
            info: ({index}) => index.info
        },
        // 状态变更事件
        actions: {
            setTitle
        }
    }
}
Modules

场景:使用单一状态数,导致应用的所有状态集中到一个很大的对象。但是,当应用变得很大时,sotre对象会变得难以维护。

Vuex允许将sotre分割到模块(module),每个模块拥有自己的state,mutation,action,getters.

import Vuex from "vuex"
import Vue from "vue"
import movie from "./modules/movie"

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    movie
  }
});
Store配置项
new Vuex.Store({
    state: {},  // 初始状态
    
    actions: {}, // 执行 mutation,异步.
    
    getters: {}, // 全局方法,二次加工数据
    
    mutations: {} // Store 与外界交互的入口
    
});

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87920.html

相关文章

发表评论

0条评论

animabear

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<