【问题标题】:How to avoid the need of writing this.$store.state.donkey all the time in Vue?如何避免在 Vue 中一直写 this.$store.state.donkey?
【发布时间】:2016-12-01 11:31:47
【问题描述】:

我正在学习 Vue,我注意到我在任何地方或多或少都有以下语法。

export default {
  components: { Navigation, View1 },
  computed: {
    classObject: function() {
      return {
        alert: this.$store.state.environment !== "dev",
        info: this.$store.state.environment === "dev"
      };
    }
  }
}

一直写出this.$store.state.donkey 很痛苦,它也降低了可读性。我感觉到我正在以一种不太理想的方式来做这件事。我应该如何参考商店的状态?

【问题讨论】:

    标签: javascript vue.js vuex


    【解决方案1】:

    您可以为状态和吸气剂设置计算属性,即

    computed: {
        donkey () {
            this.$store.state.donkey
        },
        ass () {
            this.$store.getters.ass
        },
        ...
    

    虽然您仍然需要调用 $state.store,然后才能在您的虚拟机上引用驴或驴...

    为了让事情变得更简单,你可以拉入 vuex 地图助手并使用它们来找到你的驴子……或驴子:

    import { mapState, mapGetters } from 'vuex'
    
    default export {
    
        computed: {
    
            ...mapState([
                'donkey',
            ]),
    
            ...mapGetters([
                'ass',
            ]),
    
            ...mapGetters({
                isMyAss: 'ass', // you can also rename your states / getters for this component
            }),
    

    现在,如果您查看this.isMyAss,您会发现...您的ass

    在此值得注意的是,getter、mutations 和 action 是全局的 - 因此它们会直接在您的商店中引用,即分别为 store.gettersstore.commitstore.dispatch。无论它们是在模块中还是在商店的根目录中,这都适用。如果它们在模块中,请检查命名空间以防止覆盖以前使用的名称:vuex docs namespacing。但是,如果您要引用模块状态,则必须在模块名称前面加上 store.state.user.firstName 在此示例中 user 是一个模块。


    23/05/17 编辑

    自从撰写本文以来,Vuex 已经更新,它的命名空间功能现在是您使用模块时的首选。只需将namespace: true 添加到您的模块导出中,即

    # vuex/modules/foo.js
    export default {
      namespace: true,
      state: {
        some: 'thing',
        ...
    

    foo 模块添加到您的 vuex 商店:

    # vuex/store.js
    import foo from './modules/foo'
    
    export default new Vuex.Store({
    
      modules: {
        foo,
        ...
    

    然后,当您将该模块拉入您的组件时,您可以:

    export default {
      computed: {
        ...mapState('foo', [
          'some',
        ]),
        ...mapState('foo', {
          another: 'some',
        }),
        ...
    

    这使得模块使用起来非常简单和干净,如果您将它们嵌套多个层次,它是一个真正的救星:namespacing vuex docs


    我整理了一个示例小提琴来展示您可以参考和使用 vuex 商店的各种方式:

    JSFiddle Vuex Example

    或查看以下内容:

    const userModule = {
    
    	state: {
            firstName: '',
            surname: '',
            loggedIn: false,
        },
        
        // @params state, getters, rootstate
        getters: {
       		fullName: (state, getters, rootState) => {
            	return `${state.firstName} ${state.surname}`
            },
            userGreeting: (state, getters, rootState) => {
            	return state.loggedIn ? `${rootState.greeting} ${getters.fullName}` : 'Anonymous'
            },
        },
        
        // @params state
        mutations: {
            logIn: state => {
            	state.loggedIn = true
            },
            setName: (state, payload) => {
            	state.firstName = payload.firstName
            	state.surname = payload.surname
            },
        },
        
        // @params context
        // context.state, context.getters, context.commit (mutations), context.dispatch (actions)
        actions: {
        	authenticateUser: (context, payload) => {
            	if (!context.state.loggedIn) {
            		window.setTimeout(() => {
                    	context.commit('logIn')
                    	context.commit('setName', payload)
                    }, 500)
                }
            },
        },
        
    }
    
    
    const store = new Vuex.Store({
        state: {
            greeting: 'Welcome ...',
        },
        mutations: {
            updateGreeting: (state, payload) => {
            	state.greeting = payload.message
            },
        },
        modules: {
        	user: userModule,
        },
    })
    
    
    Vue.component('vuex-demo', {
    	data () {
        	return {
            	userFirstName: '',
            	userSurname: '',
            }
        },
    	computed: {
        
            loggedInState () {
            	// access a modules state
                return this.$store.state.user.loggedIn
            },
            
            ...Vuex.mapState([
            	'greeting',
            ]),
            
            // access modules state (not global so prepend the module name)
            ...Vuex.mapState({
            	firstName: state => state.user.firstName,
            	surname: state => state.user.surname,
            }),
            
            ...Vuex.mapGetters([
            	'fullName',
            ]),
            
            ...Vuex.mapGetters({
            	welcomeMessage: 'userGreeting',
            }),
            
        },
        methods: {
        
        	logInUser () {
            	
                this.authenticateUser({
                	firstName: this.userFirstName,
                	surname: this.userSurname,
                })
            	
            },
        
        	// pass an array to reference the vuex store methods
            ...Vuex.mapMutations([
            	'updateGreeting',
            ]),
            
            // pass an object to rename
            ...Vuex.mapActions([
            	'authenticateUser',
            ]),
            
        }
    })
    
    
    const app = new Vue({
        el: '#app',
        store,
    })
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex"></script>
    
    <div id="app">
    
        <!-- inlining the template to make things easier to read - all of below is still held on the component not the root -->
        <vuex-demo inline-template>
            <div>
                
                <div v-if="loggedInState === false">
                    <h1>{{ greeting }}</h1>
                    <div>
                        <p><label>first name: </label><input type="text" v-model="userFirstName"></p>
                        <p><label>surname: </label><input type="text" v-model="userSurname"></p>
                        <button :disabled="!userFirstName || !userSurname" @click="logInUser">sign in</button>
                    </div>
                </div>
                
                <div v-else>
                    <h1>{{ welcomeMessage }}</h1>
                    <p>your name is: {{ fullName }}</p>
                    <p>your firstName is: {{ firstName }}</p>
                    <p>your surname is: {{ surname }}</p>
                    <div>
                        <label>Update your greeting:</label>
                        <input type="text" @input="updateGreeting({ message: $event.target.value })">
                    </div>
                </div>
            
            </div>        
        </vuex-demo>
        
    </div>

    如您所见,如果您想引入突变或操作,这将以类似的方式完成,但在您的方法中使用 mapMutationsmapActions


    添加 Mixins

    要扩展上述行为,您可以将其与 mixin 结合使用,然后您只需设置一次上述计算属性并将 mixin 拉入需要它们的组件:

    animals.js(混合文件)

    import { mapState, mapGetters } from 'vuex'
    
    export default {
    
        computed: {
    
           ...mapState([
               'donkey',
               ...
    

    您的组件

    import animalsMixin from './mixins/animals.js'
    
    export default {
    
        mixins: [
            animalsMixin,
        ],
    
        created () {
    
            this.isDonkeyAnAss = this.donkey === this.ass
            ...
    

    【讨论】:

    • 的同义词肯定+1应用得这么顺利,哈哈哈。
    • 模块状态图助手速记格式怎么样?我无法让它工作,状态不是全局的,所以你必须将它作为 state.module 引用,这对于帮助者来说并不是很有帮助。
    猜你喜欢
    • 2016-09-21
    • 2021-09-08
    • 2020-09-24
    • 2021-05-10
    • 2020-09-11
    • 2010-10-01
    相关资源
    最近更新 更多