I am following this CodePen, and trying to fit it into the default VueJS 2.0 Boilerplate. This is how I would split the files up:
App.vue
main.js
components/Transitions.vue
components/Controls.vue
components/Page.vue
I am having huge problems getting this to run. E.g. my App.vue does not find the state
. This is how I defined it in main.js:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
const state = {
animations: ['fade', 'slide', 'slideUp', 'zoom', 'flipX', 'flipY'],
view: 'slide'
}
new Vue({
render: h => h(App),
data() {
return this.state
}
}).$mount('#app')
This is my App.vue:
<template>
<div id="app">
<component :is="state.view">
<h1>{{ state.view }}</h1>
</component>
<controls></controls>
</div>
</template>
This would be my controls:
<template id="controls">
<ul class="controls">
<li v-for="(animation, index) in state.animations" v-bind:key="index" @click.prevent="setView(animation)" v-bind:class="{ 'active': animation === state.view }">
{{ animation }}
</li>
</ul>
</template>
<script>
export default {
template: '#controls',
methods: {
setView(animation) {
this.state.view = animation
}
}
}
</script>
..and so forth. Unfortunately I am getting:
[Vue warn]: data functions should return an object:
https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function
(found in <Root>) vue.runtime.esm.js:619
[Vue warn]: Property or method "state" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
---> <App> at src/App.vue
<Root> vue.runtime.esm.js:619
[Vue warn]: Error in render: "TypeError: this.state is undefined"
What am I doing wrong here? How to get this thing to run?
Attaching data properties to the root instance does not make them globally available in all descendant components (which appears to be what you attempted). There are actually a few ways to share state across components, including Vuex or global event bus (e.g., using $root.emit()
and $root.on()
). However, another simple solution is to use Vue.observable along with a mixin, exported from a shared file:
stateMixin.js:
import { observable } from "vue";
const state = observable({
animations: ["fade", "slide", "slideUp", "zoom", "flipX", "flipY"],
view: "slide"
});
// a mixin that declares a data propety named `state`
export default {
data() {
return {
state
};
}
};
Then, you could import that file into any component that needs to access state
:
App.vue:
import stateMixin from '@/stateMixin'
export default {
mixins: [stateMixin],
mounted() {
console.log(this.state.view) // <-- stateMixin provides access to `state`
}
}
demo of that Codepen in Codesandbox
Also note that since you're converting to single-file-components (SFC), you should not export a template
property. The SFC itself declares the template already, and the compiler knows to use that by default.