Vue.js with pinia npm server error variable is assigned a value but never used - vue.js

I am using this video https://www.youtube.com/watch?v=Ok6vO98RV_Q&t=108s, but I keep getting the error: "error 'counter' is assigned a value but never used no-unused-vars". What am I missing?
<template>
{{ counter }}
</template>
<script>
import { storeToRefs } from "pinia";
import useStore from "../store/useStore";
const main = useStore;
const { counter } = storeToRefs(main);
</script>
store:
import { defineStore } from "pinia";
// import { auth } from "./auth.module";
export const useStore = defineStore("main", {
state: () => ({
counter: null,
}),
});

You have to specify <script setup> for Composition API or else you have to expose the properties manually to the template by returning them.
<template>
{{ counter }}
</template>
<script setup>
import { storeToRefs } from "pinia";
import useStore from "../store/useStore";
const main = useStore();
const { counter } = storeToRefs(main);
</script>

Related

Using Pinia with Vue.js Web components

Question has been updated
I'm trying to use a Pinia's store with web components created with Vue.js but I have this error in the console:
[Vue warn]: injection "Symbol(pinia)" not found at <HelloWorld.ce msg="message" >
I have a dead simple exemple.
main.ts
import { defineCustomElement } from 'vue'
import HelloWorld from './components/HelloWorld.ce.vue'
const ExampleElement = defineCustomElement(HelloWorld)
customElements.define('hello-world', ExampleElement)
store.ts
import { defineStore, createPinia, setActivePinia } from "pinia";
setActivePinia(createPinia());
export const useCounterStore = defineStore('counter', {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++;
},
},
});
HelloWorld.ce.vue
<script setup lang="ts">
import { ref } from 'vue'
import { useCounterStore } from '../store.ts'
defineProps<{ msg: string }>()
const store = useCounterStore()
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" #click="store.increment()">count is {{ store.counter }}</button>
</div>
</template>
You're recreating pinia in the store after already creating it in main.js. Remove these lines from your store:
import { createPinia } from 'pinia'
const pinia = createPinia()

Vue 2 with Composition API Reactive

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;
}
}
}

Vue3.js and Pinia: Why is my store state undefined in VueDevtools?

I am using Vue 3 with Pinia ^2.0.14. I'm importing Pinia into the app in main.ts like so:
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App).use(pinia).mount('#app')
I'm creating the store language.ts like so:
import { defineStore } from 'pinia'
export const useLanguageStore = defineStore({
id: 'language',
state: () => ({
language: 'English',
languages: ['English', 'Spanish'],
}),
})
and using it in LanguageDropdown.vue like so:
<script setup lang="ts">
import { useLanguageStore } from '#/store/language.ts'
const languageStore = useLanguageStore()
</script>
<template>
<select
v-model="languageStore.language">
<option
v-for="language in languageStore.languages"
:key="language"
:value="language"
>
{{ language }}
</option>
</select>
</template>
The code works as expected, but in the Vue devtools inspector languageStore.language, languageStore.languages, and language.state are undefined. Why would that be?
screen shot of Vue devtools inspector
I found a away to solve it, though I think its not perfect
// should use computed
const languages = computed(() => languageStore.languages )

Is there a way to share reactive data between random components in Vue 3 Composition API?

Having some reactive const in "Component A," which may update after some user action, how could this data be imported into another component?
For example:
const MyComponent = {
import { computed, ref } from "vue";
setup() {
name: "Component A",
setup() {
const foo = ref(null);
const updateFoo = computed(() => foo.value = "bar");
return { foo }
}
}
}
Could the updated value of 'foo' be used in another Component without using provide/inject?
I am pretty new in the Vue ecosystem; kind apologies if this is something obvious that I am missing here.
One of the best things about composition API is that we can create reusable logic and use that all across the App. You create a composable functions in which you can create the logic and then import that into the components where you want to use it. Not only does this make your component much cleaner but also your APP much more maintainable. Below is a simple example of counter to show how they can be used. You can find working demo here:
Create a composable function for counter:
import { ref, computed } from "vue";
const counter = ref(0);
export const getCounter = () => {
const incrementCounter = () => counter.value++;
const decrementCounter = () => counter.value--;
const counterPositiveOrNegitive = computed(() =>
counter.value >= 0 ? " Positive" : "Negitive"
);
return {
counter,
incrementCounter,
decrementCounter,
counterPositiveOrNegitive
};
};
Then you can import this function into your components and get the function or you want to use. Component to increment counter.
<template>
<div class="hello">
<h1>Component To Increment Counter</h1>
<button #click="incrementCounter">Increment</button>
</div>
</template>
<script>
import { getCounter } from "../composables/counterExample";
export default {
name: "IncrementCounter",
setup() {
const { incrementCounter } = getCounter();
return { incrementCounter };
},
};
</script>
Component to decrement counter:
<template>
<div class="hello">
<h1>Component To Decrement Counter</h1>
<button #click="decrementCounter">Decrement</button>
</div>
</template>
<script>
import { getCounter } from "../composables/counterExample";
export default {
name: "DecrementCounter",
setup() {
const { decrementCounter } = getCounter();
return { decrementCounter };
},
};
</script>
Then in the main component, you can show the counter value.
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<div class="counters">
<IncrementCounter />
<DecrementCounter />
</div>
<h3>Main Component </h3>
<p>Counter: {{ counter }}</p>
<p>{{ counterPositiveOrNegitive }}</p>
</template>
<script>
import IncrementCounter from "./components/IncrementCounter.vue";
import DecrementCounter from "./components/DecrementCounter.vue";
import { getCounter } from "./composables/counterExample";
export default {
name: "App",
components: {
IncrementCounter: IncrementCounter,
DecrementCounter: DecrementCounter,
},
setup() {
const { counter, counterPositiveOrNegitive } = getCounter();
return { counter, counterPositiveOrNegitive };
},
};
Hope this was somewhat helpful. You can find a working example here:
https://codesandbox.io/s/vue3-composition-api-blfpj

Type 'true' is not assignable to type 'Ref<boolean>'

I have the following code:
<!-- App.vue -->
<template>
<button #click="login">Login</button>
</template>
<script lang="ts">
import { loggedIn } from '../state'
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
loggedIn,
}
},
methods: {
login() {
this.loggedIn = true
}
}
})
</script>
// state.ts
import { reactive, ref } from 'vue'
export const loggedIn = ref(true)
The code above has a compilation error (which shows both in VS Code and from vue-cli-service serve)
TS2322: Type 'true' is not assignable to type 'Ref<boolean>'.
> | this.loggedIn = true
I'm pretty sure that's how I'm supposed to do it, so I'm not sure why I'm getting an error. I can change the code to this and the error goes away: this.loggedIn.value = true But I'm pretty sure that's not how its supposed to work, and I get this runtime error:
Cannot create property 'value' on boolean 'false'
Why am I getting this compilation error in my original code?
Source: https://codesandbox.io/s/sad-cdn-ok40d
App.vue
<!-- App.vue -->
<template>
<div>
<button #click="login">Login</button>
<div>{{ data }}</div>
</div>
</template>
<script lang="ts">
import { loggedIn } from "./state";
export default {
name: "App",
setup() {
const data = loggedIn();
const login = () => (data.value = !data.value);
return { data, login };
},
};
</script>
State.ts
import { ref } from "vue";
export const loggedIn = () => ref(false);
Main.js
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
So the thing is, if we use the composition API, we should use the setup() method to setup out data and methods.
Since ref uses the .value to change the value, we don't need reactive.
Reactive is used for object values - which it will add a Proxy to watch over the key/values of the object.
In this case, we should use ref.