unable to access vuex store property in safari. code is working fine in Chrome - javascript

I am desperately needing some help with vuejs vuex store. it is working absolutely fine in chrome but in safari store property is not being picked up. basically I have stored a user object in Vuex store as follows: -
here is the image of my code
here is the image of within component where I am trying to access the property from store
here is the image of when axios call is made and within response I am triggering the mutation
state:{
user:{},
student:{}
},
mutations:{
setUser(state,payload) {
state.user = payload;
},
setLoggedIn (state,payload) {
state.isLoggedIn = payload;
},
setStudent(state,payload){
state.student = payload;
}
},
getters:{
isStudent: state => {
if(state.user.user_type === 'student') {
return true;
}
}
}
I am calling the mutation from inside the login component whilst executing axios call request and setting the user and student through appropriate commit from the component.
However, when I am trying to access the user property inside the component, it works fine for Chrome but it is not working for Safari. Here is how I am calling for state user property inside the component: -
computed:{
computedStatus(){
return this.$store.state.isLoggedIn;
},
computedUserType(){
return this.$store.state.user.user_type;
},
isUserStudent(){
return this.$store.getters.isStudent;
}
}
The property isUserStudent is used inside the component and is a dependency to further functionalities. This property is assessed correctly and as expected inside Chrome/Firefox, but in safari it is not being assessed. I am really puzzled what's going on here and hope that someone can support please

Related

How to async global Mixin data in Nuxt JS?

First, let me share my workflow. In my nuxt app, I am trying to track if the user is from desktop or mobile by getting the window width of the user. To do that,
Firstly, I am using js's window object in my default.vue to update the height and width variable in my store. Here is the code
//default.vue
created() {
if (process.browser) {
window.addEventListener('resize', this.handleResize);
this.handleResize(window.innerHeight, window.innerWidth);
}
},
}
methods: {
handleResize() {
this.$store.commit('setwindowheightwidth', {
height: window.innerHeight,
width: window.innerWidth
})
},
}
After that, I have created a plugin to keep my mixins. And in the mixin, I am populating my isMobile variable by getting the width variable value from store.
import Vue from "vue"
export default ({store}) => {
// Make sure to pick a unique name for the flag
// so it won't conflict with any other mixin.
if (!Vue.__my_mixin__) {
Vue.__my_mixin__ = true
Vue.mixin({
data: function() {
return {
isMobile: store.getters.windowWidth<768,
}
},
}) // Set up your mixin then
}
}
Now I am getting this data in my every component and pages, just as I was intending. But when I am loading the page first time, or refreshing the page, the value is returning true! Even when the actual value is false. But if I go to other page by navigating or come back to the initial one (without refreshing), I am getting the actual value. So it seems for some reason the value is not updating on initial loading of any of my pages. Usually I fix this kind of issue by getting the data using async-await, but not sure where to use that here. How can I update the mixin data from it's inital state on my page load?
I think, if you use computed property, instead of data value, your problem will be solved.
Also, you can install #nuxt-device module and use it to detect current device in each page.
If these approaches don't solved your problem, just store the values in the state and persist them by cookies.
import Vue from "vue"
export default ({store}) => {
// Make sure to pick a unique name for the flag
// so it won't conflict with any other mixin.
if (!Vue.__my_mixin__) {
Vue.__my_mixin__ = true
Vue.mixin({
computed:{
isMobile(){
return store.getters.windowWidth<768;
}
}
}) // Set up your mixin then
}
}

Page not loaded on refresh using vuex and getter

Trying to solve page refresh issue that occurs using vuex and getters. I must be missing something on how the reactivity works, but haven't been able to identify what after searching around and reading vue pages on reactivity.
As an example, I have a component that will initially load just fine:
Create lifecycle dispatches action to retrieve data from API and push to array in state
Computed property in component retrieves data using getter (filter array to specific person)
Component displays a few properties in array
When page is refreshed it seems that the action is called again and data retrieved but it doesn't seem like the getter works correctly to get the new data and page does not load. If I test accessing the data in the state directly then refresh works fine. So it seems that the data is properly loaded to the state when refreshing but the getter somehow doesn't have it?
Appreciate any help!
Component:
<script>
export default {
props: ["id"],
computed: {
player() {
return this.$store.getters["player/getPlayerById"](this.id);
}
},
created() {
this.$store.dispatch("player/fetchPlayer", this.id);
}
};
</script>
getter:
getPlayerById: state => id => {
return state.players.find(plr => plr.PlayerID === id);
}
action:
var promise = EventService.getPlayer(id)
.then(response => {
commit("ADD_PLAYER", response.data);
})
ADD_PLAYER mutation:
ADD_PLAYER(state, player) {
state.players.push(player[0]);
}

Sending a post request to jsonplaceholder fails in React Redux

I made a simple React Redux application that fetches a list of posts from jsonplaceholder and within it is a form that allows users to send a POST request. When I send a post request according to Redux DevTools extension it is added successfully marked as post number 101. Here is its snapshot
but the problem is after clicking the submit button 3 times it shows up on the screen.
The first two clicks show neither the title nor its body but it starts showing up on the third click.
This is Posts.jsx file and here is how I used componentDidUpdate to update the component after post request.
class Posts extends Component {
componentDidMount(){
this.props.fetchPosts();
}
componentDidUpdate(nextProps) {
if (nextProps.newPost) {
this.props.posts.unshift(nextProps.newPost);
}
}
renderPosts(){ // cutted for brevity }
render() {
return (
{this.renderPosts()}
)
}
}
const mapStateToProps = (state) => {
return {
posts: state.posts.items,
newPost: state.posts.item,
}
}
export default connect(mapStateToProps, { fetchPosts })(Posts);
Here is its GitHub link repository.
The only error I am getting is the below error.
index.js:1 Warning: Each child in a list should have a unique "key" prop.
I don't believe this has anything to do with rendering the new post, but I already specified a "key" while looping through components.
What I am doing wrong during the course of this post request? Thank You.
You are using the wrong lifeCycle method. in order to get the nexProps you have to use componentWillReceiveProps instead of componentDidUpdate.
componentDidUpdate will give you the previous Props and previous State.
componentWillReceiveProps(nextProps) {
if (nextProps.newPost) {
this.props.posts.unshift(nextProps.newPost);
}
}
The above snippet should work.
But this method is deprecated. react introduced an alternative (kind of) of this. which is called getDerivedStateFromProps. The problem is it is a static method and you can't access previous props (this.props) inside this method.
If you need it you did something wrong as it is an anti-pattern.

Why does a reload return an empty state half of the time?

I'm creating a webshop for a hobby project in Nuxt 2.5. In the Vuex store I have a module with a state "currentCart". In here I store an object with an ID and an array of products. I get the cart from the backend with an ID, which is stored in a cookie (with js-cookie).
I use nuxtServerInit to get the cart from the backend. Then I store it in the state. Then in the component, I try to get the state and display the number of articles in the cart, if the cart is null, I display "0". This gives weird results. Half of the time it says correctly how many products there are, but the Vuex dev tools tells me the cart is null. The other half of the time it displays "0".
At first I had a middleware which fired an action in the store which set the cart. This didn't work consistently at all. Then I tried to set the store with nuxtServerInit, which actually worked right. Apparently I changed something, because today it gives the descibed problem. I can't find out why it produces this problem.
The nuxtServerInit:
nuxtServerInit ({ commit }, { req }) {
let cartCookie;
// Check if there's a cookie available
if(req.headers.cookie) {
cartCookie = req.headers.cookie
.split(";")
.find(c => c.trim().startsWith("Cart="));
// Check if there's a cookie for the cart
if(cartCookie)
cartCookie = cartCookie.split("=");
else
cartCookie = null;
}
// Check if the cart cookie is set
if(cartCookie) {
// Check if the cart cookie isn't empty
if(cartCookie[1] != 'undefined') {
let cartId = cartCookie[1];
// Get the cart from the backend
this.$axios.get(`${api}/${cartId}`)
.then((response) => {
let cart = response.data;
// Set the cart in the state
commit("cart/setCart", cart);
});
}
}
else {
// Clear the cart in the state
commit("cart/clearCart");
}
},
The mutation:
setCart(state, cart) {
state.currentCart = cart;
}
The getter:
currentCart(state) {
return state.currentCart;
}
In cart.vue:
if(this.$store.getters['cart/currentCart'])
return this.$store.getters['cart/currentCart'].products.length;
else
return 0;
The state object:
const state = () => ({
currentCart: null,
});
I put console.logs everywhere, to check where it goes wrong. The nuxtServerInit works, the commit "cart/setCart" fires and has the right content. In the getter, most of the time I get a null. If I reload the page quickly after another reload, I get the right cart in the getter and the component got the right count. The Vue dev tool says the currentCart state is null, even if the component displays the data I expect.
I changed the state object to "currentCart: {}" and now it works most of the time, but every 3/4 reloads it returns an empty object. So apparently the getter fires before the state is set, while the state is set by nuxtServerInit. Is that right? If so, why is that and how do I change it?
What is it I fail to understand? I'm totally confused.
So, you know that moment you typed out the problem to ask on Stackoverflow and after submitting you got some new ideas to try out? This was one of them.
I edited the question to tell when I changed the state object to an empty object, it sometimes returned an empty object. Then it hit me, the getter is sometimes firing before the nuxtServerInit. In the documentation it states:
Note: Asynchronous nuxtServerInit actions must return a Promise or leverage async/await to allow the nuxt server to wait on them.
I changed nuxtServerInit to this:
async nuxtServerInit ({ commit }, { req }) {
...
await this.$axios.get(`${api}/${cartId}`)
.then((response) => {
...
}
await commit("cart/clearCart");
So now Nuxt can wait for the results. The Dev Tools still show an empty state, but I think that is a bug, since I can use the store state perfectly fine in the rest of the app.
Make the server wait for results
Above is the answer boiled down to a statement.
I had this same problem as #Maurits but slightly different parameters. I'm not using nuxtServerInit(), but Nuxt's fetch hook. In any case, the idea is essentially: You need to make the server wait for the data grab to finish.
Here's code for my context; I think it's helpful for those using the Nuxt fetch hook. For fun, I added computed and mounted to help illustrate the fetch hook does not go in methods.
FAILS:
(I got blank pages on browser refresh)
computed: {
/* some stuff */
},
async fetch() {
this.myDataGrab()
.then( () => {
console.log("Got the data!")
})
},
mounted() {
/* some stuff */
}
WORKS:
I forgot to add await in front of the func call! Now the server will wait for this before completing and sending the page.
async fetch() {
await this.myDataGrab()
.then( () => {
console.log("Got the messages!")
})
},

Watcher not working with Vuex

I am having an issue with watchers not being triggered upon data change in my component. The property in the data is reactive, as it has been set upon component creation and not later on.
Here is the piece of code, in which the issue is:
https://codesandbox.io/s/nlpvz0y6m
To explain in more detail, the status property gets its status from the parent, which intern gets it from a Vuex state object, it is being passed to the component successfully, as I am able to log it and change it.
However, when I setup a watcher, to execute a function upon a change in it's value, it simply doesn't trigger. Regardless how I make the change - whether with an internal method of the component or an event.
What I need is for the watcher to trigger upon change of the status property, but am not certain why it does not reflect it at all.
The structure is as it follows: BottomBar is the parent, a bool value is passed as property to Spin.vue as a prop and then the prop is assigned to a data property on the child component.
The bool value itself, comes from index.js, where the Vuex instance is.
In the console, it is showing the following two errors
[vuex] unknown getter: isSpinning
[vuex] unknown mutation type: spinIt
The issue seems to be how the store is set up. Try this.
export const store = new Vuex.Store({
state: {
controls: {
spin: false
}
},
getters: {
isSpinning: state => {
return state.controls.spin;
}
},
mutations: {
spinIt(state) {
return (state.controls.spin = !state.controls.spin);
}
}
});
You had your mutations and getters sat inside your state. I have moved them outside, and updated the references inside to make the code work as expected.
https://codesandbox.io/s/8xyxmvr8jj

Categories