You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/faq/no-active-pinia.md
+128-11
Original file line number
Diff line number
Diff line change
@@ -15,14 +15,71 @@ While this probably goes without saying, you should start by reading the page li
15
15
16
16
Before we do a deep dive into what might be going wrong here, let's briefly cover some common problems that have quick fixes.
17
17
18
-
### Quick fix 1 - missing `setup` attribute
18
+
### Quick fix 1 - Call `app.use(pinia)` as early as possible
19
+
20
+
As implied by the error message, you might need to move the call to `app.use(pinia)` to an earlier point in your code.
21
+
22
+
In general, calls to `app.use(plugin)` need to happen before `app.mount(el)`, so the following example is unlikely to work for any plugin, not just Pinia:
23
+
24
+
```js
25
+
constpinia=createPinia()
26
+
constapp=createApp(App)
27
+
28
+
// This is the wrong order, it won't work
29
+
app.mount('#app') // [!code error]
30
+
app.use(pinia) // [!code error]
31
+
```
32
+
33
+
The order plugins are used also matters, depending on what each plugin does. This example is using Pinia and Vue Router:
34
+
35
+
```js
36
+
constpinia=createPinia()
37
+
constapp=createApp(App)
38
+
39
+
// These are in the wrong order
40
+
app.use(router) // [!code error]
41
+
app.use(pinia) // [!code error]
42
+
43
+
app.mount('#app')
44
+
```
45
+
46
+
That example is calling `app.use(router)` before `app.use(pinia)`. Most of the time that won't matter, but if something in the router tries to use the store it can fail.
47
+
48
+
In particular, the call to `app.use(router)` will immediately try to resolve any redirects. e.g.:
The `redirect` function will be called as part of `app.use(router)`, before the call to `app.use(pinia)`. As a result, the call to `useAuthStore()` will fail.
The same applies if you're using other Vue plugins, not just Vue Router.
73
+
74
+
### Quick fix 2 - Missing `setup` attribute
19
75
20
76
If you're trying to use the store in a component with `<script setup>`, make sure haven't forgotten the `setup` attribute. If you just write `<script>` it'll run too soon.
21
77
22
78
For example:
23
79
24
80
```vue
25
-
<script>
81
+
<!-- This is wrong -->
82
+
<script> // [!code error]
26
83
import { ref } from 'vue'
27
84
import { useProductsStore } from './products-store'
28
85
@@ -45,7 +102,7 @@ Here it is in a Playground:
45
102
46
103
Change `<script>` to `<script setup>` and everything works fine.
47
104
48
-
### Quick fix 2 - Invoking the store by mistake
105
+
### Quick fix 3 - Invoking the store by mistake
49
106
50
107
This example is using the Options API. The mistake is the line `...mapStores(useProductsStore())`. That should be `...mapStores(useProductsStore)` instead, without the parentheses. We need to pass in the function, not the store:
If the store call is outside a component, or in a component that isn't using `<script setup>`, make sure the call is inside a function. If it's in top-level code it will run too soon.
84
141
85
142
Here's an example using Vue Router:
86
143
87
144
```js
88
145
// This won't work, because the call is at the top level
89
-
constauthStore=useAuthStore()
146
+
constauthStore=useAuthStore()// [!code error]
90
147
91
148
router.beforeEach((to) => {
92
149
// Do something involving authStore
@@ -98,7 +155,7 @@ We can fix this by moving the store call inside the `beforeEach()` callback:
98
155
```js
99
156
router.beforeEach((to) => {
100
157
// This should work
101
-
constauthStore=useAuthStore()
158
+
constauthStore=useAuthStore()// [!code highlight]
102
159
103
160
// Do something involving authStore
104
161
})
@@ -130,7 +187,7 @@ The error is shown when step 3 occurs before step 2. The Pinia instance must be
But, in practice, it probably isn't that simple. In a real application, those 3 steps probably don't sit in the same file. More likely, they're in 3 separate files, something like this:
190
+
But, in practice, it probably isn't that simple. In a real application, those 3 steps usually don't sit in the same file. More likely, they're in 3 separate files, something like this:
134
191
135
192
```js
136
193
// useProductsStore.js
@@ -366,7 +423,7 @@ It's common to use a navigation guard to check whether a user is allowed to acce
366
423
367
424
```js
368
425
// This won't work, because the call is at the top level
369
-
constauthStore=useAuthStore()
426
+
constauthStore=useAuthStore()// [!code error]
370
427
371
428
router.beforeEach((to) => {
372
429
if (to.name!=='login'&&!authStore.isLoggedIn) {
@@ -380,7 +437,7 @@ Grabbing the store outside the callback seems like a good idea, as it avoids cal
380
437
```js
381
438
router.beforeEach((to) => {
382
439
// This will work, as the call is now inside the callback
383
-
constauthStore=useAuthStore()
440
+
constauthStore=useAuthStore()// [!code highlight]
384
441
385
442
if (to.name!=='login'&&!authStore.isLoggedIn) {
386
443
return { name:'login' }
@@ -390,6 +447,66 @@ router.beforeEach((to) => {
390
447
391
448
Even if timing weren't an issue, there are other reasons why `useAuthStore()` should be called inside the navigation guard. Again, we'll discuss those [later](#why-does-pinia-work-this-way).
392
449
450
+
### Using a property getter
451
+
452
+
[Property getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) are declared using functions, so in some cases they can be used to defer the store call.
453
+
454
+
Consider this example:
455
+
456
+
```js
457
+
import { useHistoryStore } from'./history-store'
458
+
459
+
exportdefault {
460
+
menuItems: [
461
+
{
462
+
text:'Save',
463
+
data:useHistoryStore().history// This won't work // [!code error]
464
+
},
465
+
// ...
466
+
]
467
+
}
468
+
```
469
+
470
+
The call to `useHistoryStore()` is in top-level code, so we need to move it to a function. One way to achieve that would be to use a property getter:
Note the use of the `get` keyword to declare the property. The function will be called automatically when someone tries to access the `data` property, so the consuming code won't need to worry about the function call.
487
+
488
+
### Using `computed()` or `toRef()`
489
+
490
+
In the previous example we were working with non-reactive data, so we used a property getter.
491
+
492
+
For properties inside reactive objects we can use `computed()` or `toRef()` to achieve a similar result. For example:
The `computed` ref will be automatically unwrapped by the proxy created by `reactive()`, so the consuming code doesn't need to use `.value` to access the value. We could also have used `ref()` instead of `reactive()`, the unwrapping of the nested ref would work the same way.
509
+
393
510
### An example with a component
394
511
395
512
This component is using an explicit `setup` function. Again, it might seem reasonable to put the call to `useProductsStore()` outside `setup`. But that makes it top-level code, so it'll run too soon:
@@ -399,7 +516,7 @@ This component is using an explicit `setup` function. Again, it might seem reaso
399
516
import { ref } from 'vue'
400
517
import { useProductsStore } from './products-store'
0 commit comments