Skip to content

Commit 61fee19

Browse files
Add persisting-a-store.md (#43)
1 parent 9dce460 commit 61fee19

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

docs/.vitepress/config.mts

+3
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ export default defineConfig({
177177
{
178178
text: `Why am I getting an error about 'no active Pinia'?`,
179179
link: '/faq/no-active-pinia'
180+
}, {
181+
text: 'Why is my store cleared when I reload the page?',
182+
link: '/faq/persisting-a-store'
180183
}
181184
]
182185
},

docs/faq/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Only about half the questions have complete answers. Those questions are listed
7777
<!-- Pinia -->
7878

7979
- [Why am I getting an error about 'no active Pinia'?](no-active-pinia)
80+
- [Why is my store cleared when I reload the page?](persisting-a-store)
8081

8182
---
8283

docs/faq/persisting-a-store.md

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Why is my store cleared when I reload the page?
2+
3+
The data in a store, such as [Pinia](https://pinia.vuejs.org/), is only held in memory. There isn't any built-in persistence.
4+
5+
The role of a store is to provide a central place to hold global or application-wide state, rather than keeping it in a specific component. Persisting that state is a separate concern.
6+
7+
But they are often related concerns. If you're persisting data then it typically is 'global', at least in some sense.
8+
9+
We'll discuss various approaches below for persisting data, with or without a store.
10+
11+
## Types of persistence
12+
13+
The first thing to consider is where you want to persist the data. The main options are:
14+
15+
1. On the server, e.g. in a database. This allows the data to be shared between devices or users.
16+
2. Cookies. While cookies are stored in the client, they are automatically sent as headers on HTTP requests, allowing the server to see the persisted data when handling requests.
17+
3. Client-side storage, e.g. via the [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) (`localStorage`/`sessionStorage`). These won't automatically be included in HTTP requests and have much more generous size limits than cookies. If you're using SSR then you may need to consider how you'll handle rendering on the server, as it won't have access to the persisted data in the user's browser.
18+
19+
Another alternative to consider is 'persisting' the data in the URL. This has other ramifications, such as impacting the browser Back button, but if the requirement is for state to be retained across a browser reload then maybe it should be stored in the page URL? It's usually fairly clear whether this approach is a good fit or not.
20+
21+
For the remainder of this page we're going to focus on client-side persistence, e.g. using cookies, `localStorage` or `sessionStorage`.
22+
23+
## Pinia plugins
24+
25+
There are various Pinia plugins that will handle persistence automatically. The most commonly used is:
26+
27+
- [`pinia-plugin-persistedstate`](https://prazdevs.github.io/pinia-plugin-persistedstate/)
28+
29+
It uses `localStorage` by default, or cookies if used with Nuxt (for SSR). It also supports `sessionStorage`.
30+
31+
You can find several similar libraries in the npm registry.
32+
33+
## Doing it yourself
34+
35+
If you only want to persist a small amount of data then it may be possible to do it yourself, without needing any extra libraries. For example:
36+
37+
```js
38+
import { ref, watch } from 'vue'
39+
import { defineStore } from 'pinia'
40+
41+
export const useModeStore = defineStore('mode', () => {
42+
const mode = ref(sessionStorage.getItem('mode') === 'dark' ? 'dark' : 'light')
43+
44+
watch(mode, (value) => sessionStorage.setItem('mode', value))
45+
46+
function toggleMode() {
47+
mode.value = mode.value === 'dark' ? 'light' : 'dark'
48+
}
49+
50+
return { mode, toggleMode }
51+
})
52+
```
53+
54+
- [See it in a Playground](https://play.vuejs.org/#eNp9k99v2jAQx/8VK3tIkMBpu64PCDq2qQ+dtK1a+5iXNDmCi2Nb/gFIiP99ZztAoKMPSNj3ve997s7ZJm3JBH0zyThhrZLaki2pNJQWvilFdmSuZUvSlYO0EGeCJyZYeZAofzqKfHYM0LxUikaHQhy8M/wNCkEIdQaynmM2iNetdMJm6SfMTgfJMGllDWegGuZDsi5ttbhEWsOcCXi2UsM70kLAJsgqKYwliPELS0TttJ+Zpb52OiTZgEzvydbjxRx/j1rkyAwYw6TwCWUDtAH7aKHtUjFvOiVpXeplSr7u/4xJylmzsCk27D1DJ5lPwFKrkjsI9c6czYnzkERhZzF3orIoJlY2DQ8NIXQgJoGWBjky9w8nbBHJw4Urn7qL5hqs0wKnGhGPJbxghwS4pW7XuKWJqTRTFvGtU4SXopkWiTVFct/bz8nQ9wuiebfr+GLCpE23ln5ChiUneSyDpnjAuSiODwlPhGy3MQtfkkdERkImr85aHM+s4qxaIlBU9KeFgC/hOMmjGM0mec8Zu4z8o7ZUSCkFdhtGXHQBbHK8H3qRzHAeeQ0rKyU3o1IxHy2ShbXKjPPcCbVsaCXb/J1wdkfv6G3O2WsOps2ZqGGDBYtkuPcOb/mSXwjObugN/ZLXzNh4QdFq9Krl2oA+NcPyoxrai3z7+OyKXt/S66sAFqFab9Q9lR0OyBpc25w1Z+NBF8U46D/KP9LTMZWcy/XPcGe1gwNVtYBq+Z/7N7OJoE8asJUV9DqxpcYPMIYfnn/DBv8fgvgcHEf1B8G/YCR3njHKvjtRI3ZPF2gfw7aZaF7Mw8aC8J/pATRMI+jDZH980PoR9zO9PUxx9w9yiOKn)
55+
56+
A similar approach can be used to persist a ref, without using Pinia at all:
57+
58+
```js
59+
import { ref, watch } from 'vue'
60+
61+
export const mode = ref(sessionStorage.getItem('mode') === 'dark' ? 'dark' : 'light')
62+
63+
watch(mode, (value) => sessionStorage.setItem('mode', value))
64+
65+
export function toggleMode() {
66+
mode.value = mode.value === 'dark' ? 'light' : 'dark'
67+
}
68+
```
69+
70+
- [See it in a Playground](https://play.vuejs.org/#eNp9UktP4zAQ/isjX5JKUXrYPVUJ+xIHVtoFAUdfQjpNQx07sselUpX/ztimIUiI2zy++eabx1n8Gsfy6FFsROVa248EDsmPoBrd1VKQk+JK6n4YjSU4w2C2WACZrlP4j22YYGfNAFm5Dqny2WVSV+tExYXsEA6jagjZAzgnCpim4FVPnsho+Nmqvj2EdjNxvuLGj9Gt1gnGBNV6wSYKltcaves77ms0z3AOrFK0Zhh7hfZ2pN5oHmEDMRNyjVLm5W+MkfVYXOLtHtvDJ/FndwoxKe4sOrRHlGLOUWM7pJS+fviPJ7bnJM/pFaO/SN6jM8oHjQn22+sty17gotqbuP1ed4/u+kSo3WWoIDQgp4iXgg/554vR3+V+K7/HOqkn3uLb5Xh/850t7gp4aajdzxdmcr6t1HiKGF68o3TMOsBzhy4IeyBjmw5L7nTDx8qzAMlWUNc1ZNvGHjL4cTE2kKm+21O2CsSxXZ4+LD82yiNXXfE/fuDl91zwFpCAkeBN2c7rNgy/eNN8lbYQJ40VLHrpfBCXNAV1McRL4mebXgHGRQ/Y)
71+
72+
A few notes on these examples:
73+
74+
1. Neither example will work with SSR as they're using `sessionStorage`, which won't be available on the server.
75+
2. Instead of using `watch`, the call to `setItem` could be made inside `toggleMode`. With that approach, it may also be beneficial to make the exposed ref readonly, so it can only be modified via `toggleMode`.
76+
3. `sessionStorage` only accepts string values, which is fine in this example, but may need more work if your data isn't already a string.
77+
78+
## VueUse
79+
80+
While [VueUse](https://vueuse.org/) doesn't have a specific persistence plugin for Pinia, it does provide some reactive helpers for working with `localStorage` and `sessionStore`. Much like in the previous examples, these can be used with or without Pinia:
81+
82+
```js
83+
import { defineStore } from 'pinia'
84+
import { useSessionStorage } from '@vueuse/core'
85+
86+
export const useModeStore = defineStore('mode', () => {
87+
const mode = useSessionStorage('mode', 'dark')
88+
89+
function toggleMode() {
90+
mode.value = mode.value === 'dark' ? 'light' : 'dark'
91+
}
92+
93+
return { mode, toggleMode }
94+
})
95+
```
96+
97+
- [See it in a Playground](https://play.vuejs.org/#eNqFlF1v2jAUhv+KlV0kSOCUrusFgo5t6sUmbavWXubGTQ7BxbEt26FIiP++YzsNKR3dBRL2ec/j93zAPmkYl/TJJrOEN1oZR/akNMAcfNGaHMjKqIak2xbSQp4I7rjkrJdofzqKfHYM0JxpTSOhkD07w8+okITQ1kI2IGajeN2oVros/YDZ6SgZJ42q4MRoBSsu4d4pA+d87Ani78FarqQXsvooXaIpjOYl5gdzsAs5pZLW+byf+GSkL4ZvZan3ko5JNiKLG7L3dmOOv0ftmyf7jLRiZpNigT5n1crSoYg4VdcivIbEgCMBRbdMtB44PCwWHYV8Jqng9dqlZNZd+dRDhBtwrZFYv88dD57wggM6wJZ2g8GWzm1puHbEYpYmgsl6USTOFsnN604eO/LSRJp3g4njDW2wXc+GCRk+Oc/jMwjFg4NGC5w6ngjZ72MWjt1bRI+EzB9b57A9y1LwcoOGomLYLTT4EI7zPIoRNs8HZKwy+p80TKNLJbHa0OKiC2CRs5emF8lwJ3ygSNbOaTvL81bqTU1L1eRDzXI6pZf0Iueygh1tnpA2PmXZNTNQ/Y8WVe/xUDipoOHnSC/x5QWdXtHpRS7441ljeQVbp5SwE6bPEt8Il9f0ml4FMNimg79ih9/fOV4ILi+xwk95xa2LFxRRk0ejni2YAOvW+IDDcxZXasXrk9EhTHMB5rf2P6DXI2RCqOcf4c6ZFnpn5RrKzT/un+wu+r0zgA62OPc+5pipwcXw7f0v2OH3Poir2opuS84E/4BVovUeo+xrKyu0PdAFt9/DJnJZP9jbnQPp/zp6o6EbQR9W4Ns7pR/tfqRXfRcPfwGeIvyL)
98+
99+
The VueUse helpers support various options. For example, `initOnMounted: true` can be used when working with SSR. It defers loading the persisted value until after components are mounted, allowing client-side hydration to match the server-generated HTML. e.g.:
100+
101+
```js
102+
const mode = useSessionStorage('mode', 'dark', {
103+
initOnMounted: true
104+
})
105+
```
106+
107+
Documentation:
108+
109+
- [`useStorage`](https://vueuse.org/core/useStorage/)
110+
- [`useLocalStorage`](https://vueuse.org/core/useLocalStorage/)
111+
- [`useSessionStorage`](https://vueuse.org/core/useSessionStorage/)

0 commit comments

Comments
 (0)