I am trying to use vuex-persist on nuxt.js but when try to read the data in a v-if doesn't work.
I created a new file inside plugins called vuex-persis.js with the following code:
import VuexPersistence from 'vuex-persist'
export default ({ store }) => {
new VuexPersistence({
storage: window.localStorage,
}).plugin(store);
}
and into nuxt.config.js I added the following code:
plugins: [{ src: '~/plugins/vuex-persist', mode: 'client' }],
The code that I use in order to store and get data is the following:
this.$store.commit('login', { idToken });
store.state.isLogin
and I have added the following file inside the project ./store/index.js
export const state = () => ({
isLogin: false,
idToken: '',
});
export const mutations = {
login(state, newState) {
state.isLogin = true;
state.idToken = newState.idToken;
},
logout(state) {
state.isLogin = false;
state.idToken = '';
},
};
I have the following navbar when I try to get the data from store:
navbar-button(to='/board', v-if='$store.state.isLogin')
p {{ $t("navbar_board") }}
navbar-button(v-if='$store.state.isLogin', #click.native='logout')
p {{ $t("navbar_logout") }}
but always enter in the same place, log in.
I tried to use a computed like this but doesn't work on the v-if
computed: {
isLogin: function () {
console.log(this.$store.state.isLogin);
return this.$store.state.isLogin;
},
},
the console.log prints the value stored in the browser but the console.log in node prints always the default state.
Anyway, the console.log always prints the correct value stored in the localstorage.
Any idea about how can I use that data in the v-if?
Thanks
Finally solved directly using $store.state.isLogin in the v-if
Related
I have such a problem: I need to get localStorage data before nuxt layout is loaded in pages/index.vue
/pages/index.vue
<script>
export default {
layout (context) {
if (localStorage.getItem('AUTH_TOKEN')){
this.$store.dispatch('changeAuthStatus', {
authStatus: true,
accessToken: localStorage.getItem('AUTH_TOKEN'),
profileData: JSON.parse(localStorage.getItem('PROFILE_DATA'))
}).then(() => {
this.$store.dispatch('changeLoadedStatus', {
isLoaded: true
})
})
}
else {
this.$router.push('/auth')
}
}
</script>
The error when the page is loaded: localStorage is not defined
Maybe I can get localStorage data using context? Or maybe you can suggest to me any package so I can use it in the layout function?
I found the solution:
I just installed nuxt-universal-storage module, that Amirhossein Shahbazi suggested. So I have just done this:
/pages/index.vue:
<script>
export default {
middleware: ['auth'],
layout (context) {
let currentRole = context.app.$storage.getUniversal('PROFILE_DATA')
console.log(currentRole)
let currentLayout = 'default'
let defaultRoles = ['customer_support_manager', 'checker', 'storekeeper']
let tabletRoles = ['deputy_cutting_shop']
if (defaultRoles.includes(currentRole.role)) {
currentLayout = 'default'
}
else if (tabletRoles.includes(currentRole.role)) {
currentLayout = 'tablet'
}
return currentLayout
}
</script>
/middleware/auth.js:
export default function ({ redirect, app, store }) {
// some token checkers for existing, for 401 error and for their validity
}
If I'm not mistaken, Nuxt is the SSR solution for Vue (same as Next for React), right?
If so, you don't have access to the localStorage. Server Side is not running in your browser!
This kind of code works fine
<script>
export default {
layout({ store }) {
if (process.client) {
console.log('localStorage?', localStorage.getItem('myCat'))
console.log('store?', store)
}
},
}
</script>
Because localStorage is not available on the server.
Try to use localStorage.setItem('myCat', 'Tom'), move to your page and see how it displays the localStorage and the store (don't forget to use the context since this is not available here).
You can use cookie-universal-nuxt
After login you can set "AUTH_TOKEN" as cookie instead of localStorage
window.$cookies.set('AUTH_TOKEN', token)
and you can access it in layout function as
layout (context) {
let token=context.app.$cookies.get('AUTH_TOKEN')
}
I am using vercel for NextJS and this is my setup in getStaticPaths
const paths = posts.map((post) => ({
params: { player: post.player, id: post.id },
}))
return { paths, fallback: true }
When I set the fallback to true, I have got this error in vercel:
21:55:01.736 info - Generating static pages (1752/1752)
21:55:01.736 > Build error occurred 21:55:01.739 Error: Export
encountered errors on following paths: 21:55:01.739
/clip/[player]/[id]
It is ok when fallback is set to false but I really like to set fallback set to true so that pages can be updated frequently. Any help will be greatly appreciated...
Inside your /clip/[player]/[id].js file, you need to handle the fallback state when that page is being requested on-demand.
// pages/posts/[id].js
import { useRouter } from 'next/router'
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
if (router.isFallback) {
return <div>Loading...</div>
}
// Render post...
}
// This function gets called at build time
export async function getStaticPaths() {
return {
// Only `/posts/1` and `/posts/2` are generated at build time
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
// Enable statically generating additional pages
// For example: `/posts/3`
fallback: true,
}
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return {
props: { post },
// Re-generate the post at most once per second
// if a request comes in
revalidate: 1,
}
}
export default Post
https://nextjs.org/docs/basic-features/data-fetching#fallback-true
What I did was conditionally render my component. So, my component receives the object data and if I need to use a value from data, such as "title", I will do...
data?.title
Also, for my entire return component I will conditionally render it. For example...
{data !== undefined ? (
<div className ='main-content'>
<p> This is the content that I want rendered if data is defined </p>
</div>
) : (
<div className = 'fallback-content'>
<p> This shows if data == undefined </p>
</div>
)
I am trying to make a GET request to an API, assign the response to a variable and console.log it. Currently I get null in the console and I don't know why. when I just console.log the res.data I get the data, but for some reason the value does not get assigned to the variable allBeers, how can I save the response to that variable and use it?
Here is my code:
<script>
import axios from "axios";
export default {
name: "BeerList",
data() {
return {
allBeers: null
};
},
created() {
axios.get("https://api.punkapi.com/v2/beers").then(res => {
this.allBeers = res.data;
});
console.log(this.allBeers);
}
};
</script>
Try this solution. axios.get is a promise, and console.log will happen before axios.get is completed. That's why you get null.
<script>
import axios from "axios";
export default {
name: "BeerList",
data() {
return {
allBeers: null
};
},
created() {
axios.get("https://api.punkapi.com/v2/beers").then(res => {
this.allBeers = res.data;
console.log(this.allBeers);
});
}
};
</script>
You are saving the response to 'allBeers' variable correctly. The "how to use it" part depends on what you want to do with the data. Vue's 'data' is reactive, so if you want to print it to console when it changes you should use Vue's watcher in your component:
watch: {
allBeers: function(value) {
console.log("my new beers:");
console.log(value);
}
}
As Vue is UI framework you might want to update your html with the new data, in which case you need to add html template to your component - it will be automatically re-rendered when 'allBeers' change:
template: `<span> {{ allBeers }} </span>`
I have an app built using Ember and ember-apollo-client.
// templates/collaborators.hbs
// opens an ember-bootstrap modal
{{#bs-button type="success" onClick=(action (mut createCollaborator) true)}}Create collaborator{{/bs-button}}
// submit button in modal triggers "createCollaborator" in controller
{{#each model.collaborators as |collaborator|}}
{{collaborator.firstName}} {{collaborator.lastName}}
{{/each}}
// routes/collaborators.js
import Route from '#ember/routing/route';
import { RouteQueryManager } from 'ember-apollo-client';
import query from '../gql/collaborators/queries/listing';
export default Route.extend(RouteQueryManager, {
model() {
return this.get('apollo').watchQuery({ query });
}
});
// controllers/collaborator.js
export default Controller.extend({
apollo: service(),
actions: {
createCollaborator() {
let variables = {
firstName: this.firstName,
lastName: this.lastName,
hireDate: this.hireDate
}
return this.get('apollo').mutate({ mutation, variables }, 'createCollaborator')
.then(() => {
this.set('firstName', '');
this.set('lastName', '');
this.set('hireDate', '');
});
}
}
});
Currently, after creating a collaborator the data is stale and needs a browser refresh in order to update. I'd like the changes to be visible on the collaborators list right away.
From what I understood, in order to use GraphQL with Ember, I should use either Ember Data with ember-graphql-adapter OR just ember-apollo-client. I went on with apollo because of its better documentation.
I dont think I quite understood how to do that. Should I somehow use the store combined with watchQuery from apollo? Or is it something else?
LATER EDIT
Adi almost nailed it.
mutationResult actually needs to be the mutation itself.
second param in store.writeQuery should be either data: { cachedData } or data as below.
Leaving this here as it might help others.
return this.get('apollo').mutate({
mutation: createCollaborator,
variables,
update: (store, { data: { createCollaborator } }) => {
const data = store.readQuery({ query })
data.collaborators.push(createCollaborator);
store.writeQuery({ query, data });
}
}, createCollaborator');
You can use the apollo imperative store API similar to this:
return this.get('apollo').mutate(
{
mutation,
variables,
update: (store, { data: {mutationResult} }) => {
const cachedData = store.readyQuery({query: allCollaborators})
const newCollaborator = mutationResult; //this is the result of your mutation
store.writeQuery({query: allCollaborators, cachedData.push(newCollaborator)})
}
}, 'createCollaborator')
I feel like I am running out of ideas on how to solve this issue.
So I have a component that should read a file and display some data from that file. I want to pass only the filename to component so that it can handle reading and parsing the file. To do this I added a property to the component.
The issue I seem to have is that I can't really access that property from the data function, and if I add a watcher on the property I can parse the file as expected, but I can't seem to get that data into the DOM.
This is what I have right now:
<template>
<main :key="fileName">
fileName: {{fileName}}
<div class="post">{{data}}</div>
<div class="info">
<div v-for="item in info" v-bind:key="item.name">{{item.name}}</div>
</div>
</main>
</template>
<script>
const { parse } = require("#/service/parser");
const fs = require("fs");
let postInfo = { data: "abc", info: [] };
export default {
props: ["fileName"],
watch: {
fileName: {
immediate: true,
handler: (newVal, oldVal) => {
if (newVal) {
postInfo = parse(
fs
.readFileSync(__dirname + "/../../assets/" + newVal, "utf8")
.split("\n")
);
}
}
}
},
data: () => {
return postInfo;
}
};
</script>
I am obviously completely new to Vue, and I'm probably missing something stupid here.
So what am I doing wrong and how do I get the parsed data into my DOM?
Don't use an arrow function for your data function. Arrow functions bind this to whatever context the function is declared in. You need to let Vue properly bind this to the instance it is creating. So use
data() {
return postInfo;
}
or if for some reason you need to be old school:
data: function () {
return postInfo;
}