I have a reactive store store.js:
import {reactive} from "vue";
const re = reactive({})
export default {
re
}
which I'm using inside a component to assign a text value:
store.re.blog = 'Hello World!'
How can I assign this value to state inside another component? I've tried:
const state = reactive({
content1: store.re.blog || '',
content2: store.re.blog ? store.re.blog : ''
})
both of which don't work. I want to put the value in state because in the next step I'm sending the state object via ajax request to the database.
I'm using vue 3 with script setup
It works for me:
App.vue:
<template>
<HelloWorld />
<OtherComponentReceivingStoreValue />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
import OtherComponentReceivingStoreValue from "#/components/OtherComponentReceivingStoreValue.vue";
export default defineComponent({
name: 'App',
components: {
OtherComponentReceivingStoreValue,
HelloWorld
}
});
</script>
HelloWorld.vue:
<template>
Component that initialize the store blog value
</template>
<script lang="ts" setup>
import store from '#/store'
store.re.blog = 'Hello World!'
</script>
ComponentReadingTheStore:
<template>
<div>
store value:
{{ state }}
</div>
</template>
<script lang="ts" setup>
import store from '#/store'
import {reactive} from "vue";
const state = reactive({
content1: store.re.blog || '',
content2: store.re.blog ? store.re.blog : ''
})
</script>
If what you want is to change the store in the receiver component when the first component mutate the store, you have to put a watch or make a computed.
Related
I am trying to execute a function from the Food.vue component from Page.vue.
How can I execute a function from an imported component?
I am using Vue 3 Composition API.
This is what I am trying to do:
Food.vue Component
<script setup>
var food = "blueberry"
function changeFood () {
food = "cherry";
}
</script>
<template>
<div>{{food}}</div>
</template>
Page.vue
<script setup>
import { onMounted } from "vue";
import food from "#/components/Food.vue";
onMounted(async() => {
// I want to execute changeFood() from the imported component. How can I do this?
});
</script>
<template>
<food></food>
</template>
I know this can be done with page props, but that's not what Im trying to do. I am trying to execute a function.
You have to expose the method to the parent using defineExpose;
Food.vue
<script setup>
import { ref } from "vue";
const food = ref("blueberry");
const changeFood = () => {
food.value = "cherry";
};
defineExpose({ changeFood });
</script>
<template>
<div>{{food}}</div>
</template>
Page.vue
<script setup>
import { ref, onMounted } from "vue";
import food from "#/components/Food.vue";
const myFood = ref(null);
onMounted(async() => {
if (myFood.value) {
myFood.value.changeFood();
}
});
</script>
<template>
<food ref="myFood" />
</template>
Demo
For a legacy project we need to use vue 2.
However we want to implement state by using #vue/composition-api for vue 2
But my only question is, how to use it with options api?
I have a proof of concept with a .js file
import { reactive } from '#vue/composition-api';
const state = reactive({
counter : 0
})
export default{ state }
For setup it is easy:
<template>
<h1>hi
<div>We still in it: {{ counter }}</div>
<button #click="increment">+</button>
</h1>
</template>
<script>
import { defineComponent, computed } from '#vue/composition-api'
export default defineComponent({
name: "TestStateHello",
setup() {
const store = require("./useState").default;
return {
counter: computed(() => store.state.counter),
increment: () => store.state.counter++,
};
},
})
</script>
But when i want to use regular options api to have access to reactive state of counter i don't seem to know how.
your help will be very grateful!
Just import it globally (outside of the returned options object):
<template>
<h1>hi
<div>We still in it: {{ counter }}</div>
<button #click="increment">+</button>
</h1>
</template>
<script>
import { defineComponent, computed } from '#vue/composition-api'
// Alternative (after fixing export): import {store} from './useState';
// You can use this in setup, too - no need to the require inside the setup()
const store = require("./useState").default;
export default defineComponent({
name: "TestStateHello",
computed: {
counter: () => store.state.counter,
},
methods: {
increment: () => store.state.counter++,
}
})
</script>
I suggest you change the export to:
import { reactive } from '#vue/composition-api';
const state = reactive({
counter : 0
})
export state; // < then import works as above
When dealing with options api you can make use of provide-inject-concept
How it works.
You can provide file of store in main.js like below
import GStore from "./useState"
app.provide('GStore',GStore)
Then in component you can inject that store
export default {
inject:["GStore"]
methods:{
//Code just to show how to access store counter
testingState(){
return this.GStore.state.counter;
}
}
}
I have a model class for an address where I've defined a method to return the full street (combined from two seperate properties on the address model). Now I wanted to pass such an object via props to a component and use the full street method to display it.
Unfortunately, it seems that the component loses the type of the object as the method call isn't recognized in the template...
Isn't it possible to use methods in templates?
Here's some simplified code:
Parent component:
<template>
<div>
<AddressDisplay v-bind:address="AddressModel = { street: 'Bleeker', streetNr: '1' }" />
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import AddressDisplay from '#/components/AddressDisplay.vue';
export default Vue.extend({
components: { AddressDisplay },
});
</script>
Child component:
<template>
<div>
{{ address.fullStreet }}
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
address: { type: Object, required: true },
},
created() {
console.log(this.address.type);
},
});
</script>
Type definition for model:
class AddressModel implements Model {
street = '';
streetNr = '';
get fullStreet(): string {
return this.street + ' ' + this.streetNr;
}
}
What happens: nothing! There is no error message, but nothing is displayed. The console print type 'undefined'.
Why you write it like this: v-bind:address="AddressModel = { street: 'Bleeker', streetNr: '1' }"? What do you expect? Especially when you don't even import "AddressModel". Have a look at examples https://class-component.vuejs.org/guide/class-component.html#data
This will probably work:
<template>
<div>
<AddressDisplay v-bind:address="address" />
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import AddressDisplay from '#/components/AddressDisplay.vue';
export default Vue.extend({
components: { AddressDisplay },
data(){ return {
address: { street: 'Bleeker', streetNr: '1' }
}}
});
</script>
My component does not update the loaded property when Store.loaded changes:
Component
import { Vue } from 'vue-property-decorator'
import Component from 'nuxt-class-component'
import { Store } from '../repositories'
#Component
export default class Layout extends Vue {
loaded = Store.loaded
}
Store
class Root {
loaded = false
}
export let Store = new Root()
export default Store
In your example Store is just plain function (class), without any reactivity (no Vue watchers attached for Store.loaded field).
Only properties inside component's data are reactive. If you want reactive single store outside of vue components (better for big frontend applications), you should use Vuex
Simple example will be:
App.vue:
<script>
import { mapGetters, mapMutations } from 'vuex';
import store from './store';
import ChildComponent from './components/ChildComponent.vue';
export default {
store,
components: { ChildComponent },
methods: {
...mapMutations(['toggleLoaded']),
},
computed: {
...mapGetters({
isLoaded: 'isLoaded',
}),
}
}
</script>
<template>
<div id="app">
Toggle loaded
<h3>Root component: </h3>
<div>The loaded flag is: {{ isLoaded }}</div>
<ChildComponent />
</div>
</template>
components/ChildComponent.vue:
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
isLoaded: 'isLoaded', //accessing to same data, as root through single Vuex state
}),
}
}
</script>
<template>
<div class="hello">
<h3>Child component</h3>
<div>The loaded flag is: {{ isLoaded }}</div>
</div>
</template>
And reactive Vuex store:
store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const state = {
loaded: false
};
const getters = {
isLoaded: state => state.loaded,
};
const mutations = {
toggleLoaded: (state) => {
state.loaded = !state.loaded;
}
};
export default new Vuex.Store({
state,
mutations,
// actions,
getters,
strict: true
});
You can find full source of this example on GitHub.
I am trying tp pass an id param when the user click on the link generated by but I don't see it in the html
The id should be the currentUserId set or initialised in store .. so I defined a computed prop and appropriate getter ('getCurrentUserId') which pick up the currentUserId from the state..
Where am I wrong ?
<li id="shoppinglists">Shopping Lists</li>
I should get :
href="#/shoppinglists/1"
App.vue
<template>
<div id="app">
<ul class="navigation">
<li id="home"><router-link :to="{ name: 'Home' }" >Home</router-link></li>
<li id="shoppinglists"><router-link :to="{ name: 'ShoppingLists', params: { id: currentUserId } }" >Shopping Lists</router-link></li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
import store from '#/vuex/store'
import { mapGetters } from 'vuex'
export default {
name: 'app',
computed: {
...mapGetters({ currentUserId: 'getCurrentUserId' })
},
store
}
</script>
vuex/getters.js
import _ from 'underscore'
export default {
getCurrentUserId: state => state.currentUserId,
...
}
vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import actions from './actions'
import mutations from './mutations'
Vue.use(Vuex)
const state = {
currentUserId: 1,
...
}
export default new Vuex.Store({
state,
mutations,
getters,
actions
})
Ok got it .. it's not concatenated with the ref url... but using vue web-tools I can see that' the object to: has both the path '/shoppinglists' and params: object {id: 1}... it's not obvious to switch mindset to vue behaviour ...