vuex使用

92 阅读2分钟

一、vuex

vuex 用全局单例的形式管理数据

vuex中的内容都在store实例里

image.png

vue component即view

state

vue component 中用store的state,把state放到组件的计算属性里,监听state变化做出响应的视图更新

// 在组件中用state
computed: {
   count () {
     return store.state.count
   }
 }
// 或
import { mapState } from 'vuex'
computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })

getter

getter是state的计算属性

// 在 vue component中使用getter
computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}
通过 mapGetters 访问

mutation

mutation 必须同步

在vue component 中用commit触发mutaion

在 action中用 commit触发mutation

const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

在组件中触发mutation
store.commit('increment')
或 用mapMutations
methods: {
    ...mapMutations([
      'increment', //`this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }

action

action可以异步可以同步

在vue component 中用dispatch触发action

// 在view中触发action
store.dispatch('xxx')
或 用mapActions
methods: {
    ...mapActions([
      'increment', //`this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
import { createStore } from 'vuex';
import http from '@/utils/http'

export interface IUserProps {
  isLogin: boolean;
  name?: string;
  id?: string;
}

export interface IGlobalDataProps {
  user: IUserProps;
  token: string;
}

const store = createStore({
  state(): IGlobalDataProps {
    return {
      user: {
        isLogin: false,
        name: '',
        id: ''
      },
      token: localStorage.getItem('token') || ''
    }
  },
  getters: {},
  mutations: {
    login(state: IGlobalDataProps, payload: any) {
      console.log('mutations,,,,,,,login,,,,,,');
      const token = payload.data.token;
      state.token = token;
      localStorage.setItem('token', token)
      http.defaults.headers.common.Authorization = `Bearer ${token}`;
    },
    fetchCurrentUser(state: IGlobalDataProps, payload: any) {
      console.log('mutations,,,,,,,fetchCurrentUser,,,,,,');
      state.user = {
        isLogin: true,
        name: payload.data.nickName,
        id: payload.data._id,
      }
      console.log('fetchCurrentUser mutations  payload', payload)
    },
    logout(state: IGlobalDataProps) {
      state.token = '';
      localStorage.removeItem('token');
      http.defaults.headers.common.Authorization = '';
    }
  },
  actions: {
    login(context, payload) {
      console.log('actions,,,,,,,login,,,,,,');
      return http.post('/user/login', payload)
      .then(res => {
        // TODO 如果code是其他的统一处理
        if (res.data.code === 0) {
          // 存储token
          console.log('登录成功', res);
          context.commit('login', res.data)
          // return res.data;
        }
      }).catch(error => {
        console.log('登录失败', error);
      })
    },
    fetchCurrentUser(context) {
      console.log('actions,,,,,,,fetchCurrentUser,,,,,,');
      // 这么写就可以把异步执行完 在处理接下来的事件, 把then里的结果返回出去是promise(fullfilld)
      return http.get('/user/current')
      .then(res => {
        if (res.data.code === 0) {
          console.log('获取用户信息成功', res);
          context.commit('fetchCurrentUser', res.data)
          // return res.data;
        }
      }).catch(error => {
        console.log('获取用户信息失败', error);
      })
    },
    async loginAndFetchCurrentUser(context, payload) {
      context.dispatch('login', payload).then(()=>{
        context.dispatch('fetchCurrentUser');
      });
    }
  }
})

export default store;

二、命名空间

目前是全局命名空间 默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名