Can't dispatch in mounted? vuex - javascript

Does anyone know why my state.pages doesnt get filled with the json data I fetch with axios? However, when I change something in my file and save it, so that vite will reload, the data does show up on the page. And will dissapear again when I refresh the page in the browser.
PageView:
<template>
<main v-if="page">
<h1>{{ page.title }}</h1>
<div class="content" v-html="page.content"></div>
</main>
<main v-else>
<h1>loading</h1>
</main>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
page: null,
};
},
methods: {
...mapActions({ getPages: "getPages" }),
},
computed: {
slug() {
return this.$route.params.slug;
},
getPage() {
console.log(this.$store.state.pages);
return (this.page = this.$store.state.pages.find(
(page) => page.slug === this.slug
));
},
},
mounted() {
this.$store.dispatch("getPages");
this.getPages();
this.getPage;
},
};
</script>
<style>
</style>
Vuex index:
import { createStore } from 'vuex';
import axios from 'axios';
const store = createStore({
state() {
return {
pages: [],
};
},
mutations: {
setPages(state, { response }) {
state.pages = response.data;
},
},
actions: {
getPages({ commit }) {
axios.get('../src/data/pages.json').then((response) => {
commit('setPages', { response });
});
},
},
getters: {},
});
export default store;

The race condition results because promises weren't correctly chained. As a rule of thumb, every function that uses promises should chain all promises in use and return a promise as a result of its work.
getPages is dispatched twice.
It should be:
getPages({ commit }) {
return axios....
And:
mounted() {
return this.getPages()
.then(() => {
...
});
},

Related

Vue 3 cdn example with vuex 4, but how do I access the store inside main.js?

My app structure:
> public
> scripts
> - cdn
> - vue.js
> - vuex.js
> main.js
> store.js
> index.html
Inside the head tag I have:
<script src="./scripts/cdn/vue.js"></script>
<script src="./scripts/cdn/vuex.js"></script>
<script src="./scripts/main.js" type="module"></script>
And in the body I have-
<div id="app"> <div v-for="item in items" >{{item.text}}</div> </div>
store.js
console.log('test in store.js', store.state)
const store = new Vuex.createStore({
state: {
items: [{
text: 'ahhh STORE 1'
}, {
text: 'ahhh STORE 2'
}],
},
mutations: {
},
actions: {
test({
state
}) {
console.log(state.items)
}
},
modules: {
}
})
main.js
import * as store from "./store.js";
const {
onMounted,
onUpdated,
onUnmounted,
ref,
reactive,
getCurrentInstance
} = Vue; //here define only what you need
//Define Vue app
const App = {
state: store,
// store, //using either store or state: store does not work
data() {
return {};
},
methods: {},
setup(props, context) {
onMounted(() => {
console.info("App mounted!");
console.log('mounted state', store.state)
});
onUpdated(() => {
console.info("App updated!");
});
onUnmounted(() => {
console.info("App unmounted!");
});
}
};
// Create new Vue app
const app = Vue.createApp(App);
app.use(store)
app.mount("#app");
So when the app runs, in the console it shows
test in store.js Proxy { <target>: {…}, <handler>: {…} }
But in onMounted it returns store.state as undefined.
It can work by using createStore inside main.js but I would like to keep this separated.
What am I missing and how do I make the store accessible in the main?
app.use(store) -
you have already added the store to the vue instance.
Then you can access this storage from any component, for example using:
import { mapState} from 'vuex';
...
computed: {
...mapState({
items: state => state.items
}),
},
or in setup:
import { useStore } from 'vuex';
...
setup(){
const store = useStore();
const state = store.state; // <-- state from vuex
}
Your working example:
const store = new Vuex.createStore({
state: {
items: [{
text: 'ahhh STORE 1'
}, {
text: 'ahhh STORE 2'
}],
},
mutations: {
},
actions: {
test({
state
}) {
console.log(state.items)
}
},
modules: {
}
})
const {
onMounted,
onUpdated,
onUnmounted,
ref,
reactive,
} = Vue; //here define only what you need
//Define Vue app
const App = {
data() {
return {};
},
methods: {},
computed: {
...Vuex.mapState({
items: state => state.items
}),
},
setup(props, context) {
const store = Vuex.useStore()
onMounted(() => {
console.info("App mounted!");
console.log('mounted state', store.state)
});
onUpdated(() => {
console.info("App updated!");
});
onUnmounted(() => {
console.info("App unmounted!");
});
}
};
// Create new Vue app
const app = Vue.createApp(App);
app.use(store)
app.mount("#app");
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://unpkg.com/vuex#4.0.0/dist/vuex.global.js"></script>
<div id="app">
<div v-for="item in items">{{item.text}}</div>
</div>

data from api can't assign to property in state

My project has /store.index.ts. I want to get data from api in actions block. I got data but can't assign data to property in state. I used interface because project has typescript and i used vuexStore. I wanted to work the axios.get in vuex store then i can't assign data to property of state .
/store/index.ts page:
import { createStore } from "vuex";
import axios from "axios";
export interface State {
tasks: any;
}
export default createStore<State> {
state: {
tasks: [],
},
getters: {
getAd(state) {
return state.tasks;
},
},
mutations: {
setTasks: (state, tasks) => {
state.tasks = tasks;
},
},
actions: {
async fetchProfile({ commit }) {
const response = await axios.get(
"https://5dd471358b5e080014dc51d2.mockapi.io/users/"
);
commit("setTasks", response.data);
return response.data;
},
},
modules: {},
};
newcomponent.vue page:
<template>
<div>
<h1>B12 Interactive</h1>
<div>
<h2>Skill Rating System</h2>
</div>
<div><input placeholder="Person/App/Rate" /></div>
<div>
<div class="vl"></div>
<hr />
<div class="v2"></div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { useStore } from "vuex";
export default defineComponent({
setup() {
const store = useStore();
const test = ref(
store.dispatch("fetchProfile")
); /*i can get data this line but
can't use with v:bind:key="item.id" in template block as v-for loop.This line is working in console.log() Array.length is higher than zero */
console.log(
"store:",
store.state.tasks
); /*i can't get data because data can't
assign to property in state. this line isn't working in console.log() Array.length is zero */
return {
test,
};
},
});
</script>

Pass Laravel data to Vue component using vue router

I have a laravel collection that should pass json data to a vue component
$problems = $maintenance->getMaintenanceTypes();
return new MaintenanceTypesCollection($problems);
I'm then creating a radio button using that json collection
<div v-for="m_type in maintenance_types" :key="m_type.id">
<input type="radio" v-model="form.m_type" :value="m_type.id" :id="m_type.id">
<label :for="m_type.id">{{ m_type.problem }}</label>
</div>
and the data is being passed well when I'm using Laravel web routing but when I switch to Vue router the data is not being passed at all.
For reference here is my routes/api.php
Route::get('/maintenance/types', 'Maintenance\MaintenanceTypesController#index');
Here is my Vuex store
import axios from 'axios'
import { data } from 'jquery'
export default {
namespaced: true,
state:{
maintenance_types: []
},
getters:{
maintenance_types (state) {
return state.maintenance_types
}
},
mutations:{
PUSH_M_TYPE (state, data) {
state.maintenance_types.push(...data)
}
},
actions:{
async getMaintenanceTypes ({ commit }) {
let response = await axios.get('/maintenance/types')
commit('PUSH_M_TYPE', response.data.data)
}
}
}
And here is my Vue component script logic
import { mapGetters, mapActions } from 'vuex'
import axios from 'axios'
export default {
data () {
return {
form: {
description: '',
m_type: ''
}
}
},
computed: {
...mapGetters({
maintenance_types: 'maintenance/maintenance_types'
})
},
methods: {
...mapActions({
getMaintenanceTypes: 'maintenance/getMaintenanceTypes'
}),
async submit () {
await axios.post('/api/maintenance/store', this.form)
}
},
mounted () {
this.getMaintenanceTypes()
}
}
When I'm using this Vue routing it is not working
import AppMaintenanceForm from './components/maintenance/AppMaintenanceForm.vue'
export const routes = [
{
path: '/maintenance/form',
component: AppMaintenanceForm,
name: 'MaintenanceForm'
},
]
but when I switch to Laravel's routes/web.php it is working. What could be the problem? Thanks.

How to map state back to component in Vue.js AWS Amplify auth page

I am building an authentication page with Vue.js, Vuex, and AWS Amplify.
This auth page is based off Erik Hanchett's AWS Auth Example (https://github.com/ErikCH/Aws-auth-example/blob/master/src/components/HelloWorld.vue). Erik's original demo utilized Vuex for state management, but for the sake of simplicity only employs the state handler in the store.js file.
I am attempting to reconfigure this demo so that the various methods and hooks in HelloWorld.vue are set up to also dispatch actions and commit mutations.
So far, I have been successful in setting up the findUser() method in HelloWorld.vue to dispatch actions, pass user and signedIn as payloads to their respective action handlers, and then commit mutations.
However, my issue now pertains to the computed property in the HelloWorld component.
Erik's original demo returns the state directly to the component using return this.$store.state.signedIn as seen in the computed property. Based on my experience with Vuex in other projects, I would normally use a mapState helper to map directly to the state.
Is it correct in this project to use this.$store.state.signedIn to return the state? Or should I use mapState? If so, how can I reconfigure this computed property in order to employ mapState to map directly to signedIn?
My code is below:
HelloWorld.vue
<template>
<div class="hello">
<div v-if="!signedIn">
<amplify-authenticator></amplify-authenticator>
</div>
<div v-if="signedIn">
<Home></Home>
</div>
</div>
</template>
<script>
import { Auth } from 'aws-amplify'
import { AmplifyEventBus } from 'aws-amplify-vue';
import { mapState } from 'vuex'
import Home from '../components/Home.vue'
export default {
name: 'HelloWorld',
components: {
Home
},
data() {
return {
login: '',
password: ''
}
},
props: {
msg: String,
},
created(){
this.findUser();
AmplifyEventBus.$on('authState', info => {
if(info === "signedIn") {
this.findUser();
} else {
this.$store.state.signedIn = false;
this.$store.state.user = null;
}
});
},
computed: {
signedIn(){
return this.$store.state.signedIn;
}
},
methods: {
async findUser() {
try {
const user = await Auth.currentAuthenticatedUser();
let signedIn = true
this.$store.dispatch('setUser', user)
this.$store.dispatch('setSignedIn', signedIn)
}
catch(err) {
let signedIn = false
this.$store.dispatch('setSignedIn', signedIn)
}
}
}
}
</script>
Store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: null,
signedIn: false
},
mutations: {
setUser(state, user) {
state.user = user
},
setSignedIn(state, signedIn) {
state.signedIn = signedIn
}
},
actions: {
setUser: (context, user) => {
context.commit('setUser', user)
},
setSignedIn: (context, signedIn) => {
context.commit('setSignedIn', signedIn)
}
}
})
Home.vue
<template>
<div class="goodbye">
<h1>HOME</h1><br>
<amplify-sign-out></amplify-sign-out>
</div>
</template>
<script>
import { Auth } from 'aws-amplify'
export default {
name: 'Home',
data() {
return {
login: '',
password: ''
}
},
props: {
msg: String,
},
methods: {
signOut() {
Auth.signOut()
}
}
}
</script>
The mapState helper is just sugar syntax for not repeating multiple times the whole this.$store.state.foo piece of code.
You can certainly use mapState like this
import { mapState } from 'vuex'
computed: mapState([
// map this.signedIn to this.$store.state.signedIn
'signedIn'
])
Or like this if you want to also use local properties besides the ones of mapState
import { mapState } from 'vuex'
computed:
localComputed () { /* ... */ },
...mapState([
// map this.signedIn to this.$store.state.signedIn
'signedIn'
])
Here are the docs for more information on this.

vue.js how can i use axios .get my code is doesnt working

i want use axios.get and get some data in my database but it have a error.
this is my store.js code
export default new Vuex.Store({
state: {
test: null
},
mutations: {
testt(state, payload) {
state.test = payload;
}
},
actions: {
testFun({ commit }) {
axios.get("http://localhost:8070/beer").then(response => {
let test = {
id: response.data.data.id,
title: response.data.data.title,
subtitle: response.data.data.subtitle
};
commit("testt", test);
});
}
}
});
this is my app.vue code
<script>
import { mapState, mapActions } from "vuex";
export default {
props: {
source: String
},
data: () => ({
drawer: null
}),
computed: {
...mapState(["isLogin"])
},
methods: {
...mapActions(["testFun"])
}
};
</script>
<v-list-item router :to="{name: 'test'}" exact #click="testFun()">
<v-list-item-action>
<v-icon>mdi-contact-mail</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>test</v-list-item-title>
</v-list-item-content>
</v-list-item>
this.is my testt.vue code
<script>
import { mapState } from "vuex";
export default {
computed: {
...mapState(["test"])
},
data() {
return {
beer: []
};
},
mounted() {
//
}
};
</script>
<template>
<div>
<h1>Beer List</h1>
<div v-for="beer in test" :key="beer.id">{{ beer.title }}</div>
</div>
</template>
and i have router
and my database is no problem because i texting path in my controller path it was working but it doesn't woring on vue
but result is error
this is errormessage
TypeError: Cannot read property 'title' of null
Brother in your back-end request the title variable are not exist in your json response kindly check and let me know. if you still facing any issue.
Thanks

Categories

Resources