Mutations on Page Load [Nuxt] [Vuex]

Viewed 1878

(I'm new to vue and nuxt). I currently have a <HeaderImage> component in my layouts/default.vue and would like to have each page to pass a different image url to that component.

Right now I'm using vuex $store for that purpose (but would love if there were a simpler way to pass the data), but I'm trying to figure out where in my pages/xyz.vue I should be using the mutation this.$store.commit('headerImg/setHeaderImage', 'someImage.jpg')

All of the examples I can find only use mutations on user events.

2 Answers

What you are trying to do probably doesn't have a particularly simple solution and how I would do it is use a store state element that is set by the component when it is loaded. The component would commit a mutation in the store that alters the state element. The layout would then use that state element through a getter to set the image url. Here is how I'd code that. In the store state i'd have an array of class names, let's call it 'headState', and an element that would be assigned one of those class names, called 'headStateSelect:

//store/index.js

state: {
  headState: ['blue', 'red', 'green'],
  headStateSelect : ''
}

In your component you can use fetch, or async fetch to commit a mutation that will set 'headStateSelect' with one of the 'headState' elements.

//yourComponent.vue

async fetch ({ store, params }) {
   await store.commit('SET_HEAD', 1) //the second parameter is to specify the array position of the 'headState' class you want
}

and store:

//store/index.js

mutations: {      
    SET_HEAD (state, data) {
        state.headStateSelect = state.headState[data]
    }
}

In the store we should also have a getter that returns the 'headStateSelect' so our layout can easily get it.

getters: {
            head(state) {
                return state.headStateSelect
            }
        }

finally, in the layout we can use the computed property to get our getter:

//layouts/default.vue

computed: {
    headElement() {
            return this.$store.getters.head
        }
}

and the layout can use the computed property to set a class like so:

//layouts/default.vue 

<template>
  <div :class="headElement">
  </div>
</template>

The div in the layout will now be set with the class name 'red' (ie. store.state.headState[1]) and you can have a .red css class in your layout file that styles it however you want, including with a background image.

For now I've settled on creating it like this:

~/store/header.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = () => ({
  headerImage: 'default.jpg'
})

const mutations = {
  newHeaderImage(state, newImage) {
    state.headerImage = newImage
  }
}

export default {
  namespaced: true,
  state,
  mutations
}

``

~/layouts/default.vue

<template>
  <div id="container">
    <Header />
    <nuxt />
  </div>
</template>

<script>
import Header from '~/components/Header'

export default {
  components: {
    Header
  }
}
</script>

``

~/components/Header.vue

<template>
  <header :style="{ backgroundImage: 'url(' + headerImage + ')'}" class="fixed">
    <h1>Header Text</h1>
  </header>
</template>

<script>
computed: {
  var image = this.$store.state.header.headerImage
  return require('~/assets/img/' + image)
}
</script>

``

~/pages/customHeader.vue

<template>
  <main>
    ...
  </main>
</template>

<script>
export default {
  head() {
    this.$store.commit('header/newHeaderImage', 'custom-header.jpg')
    return {
      title: this.title
    }
  }
}
</script>

But something feels off about putting the mutation in head() Is that correct?

And the next issue I am facing is how to return the header to default.jpg if a page doesn't change the state (which makes me think this is all the wrong approach).

Related