--- /dev/null
+<script setup lang="ts">
+import { useData } from 'vitepress'
+
+const { site } = useData()
+
+const translations = {
+ 'en-US': 'Vibe code Vue apps with confidence',
+ 'zh-CN': '自信地编写 Vue 应用的 Vibe 代码',
+}
+</script>
+
+<template>
+ <div class="rulekit">
+ <a
+ href="https://rulekit.dev?from=vuerouter"
+ target="_blank"
+ rel="sponsored noopener"
+ aria-label="Visit RuleKit - curated rules for Cursor, Claude Code, and more (opens in new tab)"
+ class="rulekit-link"
+ >
+ <div class="rulekit-content">
+ <div class="rulekit-left">
+ <span class="rulekit-sparkles" aria-hidden="true">✨</span>
+ <span class="rulekit-text">
+ <slot>{{ translations[site.lang] || translations['en-US'] }}</slot>
+ </span>
+ </div>
+ <div class="rulekit-right">
+ <svg
+ width="1024"
+ height="1024"
+ viewBox="0 0 1024 1024"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ role="img"
+ alt="RuleKit logo"
+ class="rulekit-logo"
+ >
+ <path
+ d="M335 694L353.947 697.225V737L335 733.775V694Z"
+ fill="currentColor"
+ />
+ <path
+ d="M355 538.234V673L335 669.766V536.078L355 538.234Z"
+ fill="currentColor"
+ />
+ <path
+ d="M259.255 329.5L313.424 338.585V414.78L374.576 425.512V350.39L422.5 359.457L422.529 391.816L399.251 388.374V443.756L375.649 440.537V460.314L313.424 449.576V430.878L287.675 426.585L286.602 367.561L259.255 364V329.5Z"
+ fill="currentColor"
+ />
+ <path
+ d="M398.897 113.5L647.031 158.597V199L676.034 205.5V276L836.085 304.623L896.239 362.605V498.968L873.681 516.147V778.5L914.5 792.095L755.522 914.5L180.84 802.832L130.354 738.409V472.125L103.5 457.092V336.835L164.728 270.264L291.48 205.5L321.557 211V176.85L350.56 165.5V139L398.897 113.5ZM379.562 148.933V184L350.56 182.218L349.485 259.527L379.562 263.822V184L582.581 218.725V300.328L622.325 307V224.094L598.693 220.873V188.661L379.562 148.933ZM433.271 218.725V234.831L561.097 257.379V240.2L433.271 218.725ZM291.48 234.831L223.807 272.412L740.484 364.752L802.786 325.024L673.885 302.476L622.325 330L561.097 319V282L433.271 259.527L389.23 285.296L321.557 275V240.2L291.48 234.831ZM180.84 288.517L128.206 343.277V440.537L233.475 461.387L232.401 360.457L259.255 364V446L284.103 449.576V476.42L311.889 480.714V750L373.117 762L374.191 691.165V493.599L399.251 497V472.125L422.5 476.42L422.529 391.816L449.383 396.964V500L543.911 516V414.143L571.839 418.438V388.374L624.474 396.964V423.807L652.402 428V534.5L778.08 551.5V443.756L731 392.244L180.84 288.517ZM831.789 336.835L757.671 383.005L796.341 423.807L871.533 374.416L831.789 336.835ZM807.083 445.281V529.032L871.533 486.083V404.48L807.083 445.281ZM571.839 449.576V521.516L587 524.5V592L606.213 595.603V527.5L624.474 531V458.5L571.839 449.576ZM155.06 472.125V729.5L191.5 778.5L713 880.5L754.448 853.298V579.497L635.215 560.17V601L682.479 609.562V649.29L663.144 647V682.575L682.479 684.723L683.5 814.5L652.402 808.201V839L543.911 819.5V788.874L511.685 783.505V654.5L532.095 658.5V623.52L511.685 620.299V578.424L557.875 585.94V545.138L422.5 521.516L402.12 538.234V654.658V766.326L373.117 762V791.021L311.889 778.5V750L285.035 744.851V512.926L264.5 493.599L155.06 472.125ZM778.08 579.497L780.228 833.971L847.901 781.358V538.234L778.08 579.497ZM561.097 627.5V664.5L543.911 661V788.874L565.394 793.169L567 669L584.729 672V632.5L561.097 627.5ZM611.583 639.626V676.5L628.77 679V802.832L652.402 808.201V682.575L635.215 680.428V643L611.583 639.626Z"
+ fill="currentColor"
+ />
+ </svg>
+ <span class="rulekit-title">RuleKit</span>
+ </div>
+ </div>
+ </a>
+ </div>
+</template>
+
+<style scoped>
+.rulekit {
+ margin: 1rem 0;
+}
+
+.rulekit-title {
+ font-family:
+ 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
+ 'Liberation Mono', 'Courier New', monospace;
+}
+
+.rulekit-link {
+ display: block;
+ padding: 1rem 1.5rem;
+ border-radius: 12px;
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+ border: 1px solid #dee2e6;
+ text-decoration: none;
+ color: #212529;
+ transition: all 0.3s ease;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ position: relative;
+ overflow: hidden;
+}
+
+.rulekit-link:visited {
+ color: #212529;
+}
+
+.rulekit-link:focus {
+ outline: 2px solid #0066cc;
+ outline-offset: 2px;
+}
+
+.rulekit-link:focus:not(:focus-visible) {
+ outline: none;
+}
+
+.rulekit-link::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(255, 255, 255, 0.4),
+ transparent
+ );
+ transition: left 0.6s ease;
+}
+
+.rulekit-link:hover::before {
+ left: 100%;
+}
+
+.rulekit-link:hover {
+ text-decoration: none !important;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ background: linear-gradient(135deg, #f1f3f4 0%, #e2e6ea 100%);
+}
+
+.rulekit-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+ position: relative;
+ z-index: 2;
+}
+
+.rulekit-left {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.rulekit-right {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.rulekit-sparkles {
+ font-size: 1.5rem;
+}
+
+.rulekit-logo {
+ width: 2rem;
+ height: 2rem;
+ flex-shrink: 0;
+ color: #495057;
+}
+
+.rulekit-text {
+ font-weight: 500;
+ font-family:
+ 'Spectral', ui-serif, system-ui, sans-serif, 'Apple Color Emoji',
+ 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+ font-size: 0.95rem;
+ line-height: 1.4;
+}
+
+/* Dark mode styles */
+.dark .rulekit-link {
+ background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
+ border-color: #404040;
+ color: #e5e5e5;
+}
+
+.dark .rulekit-link::before {
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(255, 255, 255, 0.15),
+ transparent
+ );
+}
+
+.dark .rulekit-link:hover {
+ text-decoration: none !important;
+ background: linear-gradient(135deg, #262626 0%, #363636 100%);
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
+}
+
+.dark .rulekit-logo {
+ color: #ffffff;
+}
+
+.dark .rulekit-text {
+ color: #e5e5e5;
+}
+
+.dark .rulekit-link:visited {
+ color: #e5e5e5;
+}
+
+.dark .rulekit-link:focus {
+ outline-color: #66b3ff;
+}
+</style>
import VueSchoolLink from './components/VueSchoolLink.vue'
import VueMasteryLogoLink from './components/VueMasteryLogoLink.vue'
import MasteringPiniaLink from './components/MasteringPiniaLink.vue'
+import RuleKitLink from './components/RuleKitLink.vue'
import status from '../translation-status.json'
const i18nLabels = {
app.component('VueSchoolLink', VueSchoolLink)
app.component('VueMasteryLogoLink', VueMasteryLogoLink)
app.component('MasteringPiniaLink', MasteringPiniaLink)
+ app.component('RuleKitLink', RuleKitLink)
},
}
border-left: 7px solid currentColor;
}
+a.cta.rulekit {
+ font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
+}
+
+a.cta.rulekit::before {
+ content: '';
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ background-image: url('/rulekit-logo.svg');
+ background-size: 16px;
+ background-repeat: no-repeat;
+ background-position: center;
+ margin-right: 0.5em;
+ vertical-align: middle;
+ filter: brightness(0); /* Make it black by default */
+}
+
+html.dark a.cta.rulekit::before {
+ filter: brightness(0) invert(1); /* Make it white in dark mode */
+}
+
@media (max-width: 420px) {
a.cta.cta.vue-mastery {
max-width: 320px;
Keep in mind that **you can only return writable state** (e.g. a `ref()`). Here are some examples of composables that you can use:
+<RuleKitLink />
+
- [useLocalStorage](https://vueuse.org/core/useLocalStorage/)
- [useAsyncState](https://vueuse.org/core/useAsyncState/)
# Composing Stores
+<RuleKitLink />
+
Composing stores is about having stores that use each other, and this is supported in Pinia. There is one rule to follow:
If **two or more stores use each other**, they cannot create an infinite loop through _getters_ or _actions_. They cannot **both** directly read each other state in their setup function:
# HMR (Hot Module Replacement)
+<RuleKitLink />
+
Pinia supports Hot Module replacement so you can edit your stores and interact with them directly in your app without reloading the page, allowing you to keep the existing state, add, or even remove state, actions, and getters.
At the moment, only [Vite](https://vitejs.dev/guide/api-hmr.html#hmr-api) is officially supported but any bundler implementing the `import.meta.hot` spec should work (e.g. [webpack](https://webpack.js.org/api/module-variables/#importmetawebpackhot) seems to use `import.meta.webpackHot` instead of `import.meta.hot`).
# Cookbook
+<RuleKitLink />
+
- [Migrating from Vuex ≤4](./migration-vuex.md): A migration guide for converting Vuex ≤4 projects.
- [HMR](./hot-module-replacement.md): How to activate hot module replacement and improve the developer experience.
- [Testing Stores (WIP)](./testing.md): How to unit test Stores and mock them in component unit tests.
# Migrating from 0.x (v1) to v2
+<RuleKitLink />
+
Starting at version `2.0.0-rc.4`, pinia supports both Vue 2 and Vue 3! This means, all new updates will be applied to this version 2 so both Vue 2 and Vue 3 users can benefit from it. If you are using Vue 3, this doesn't change anything for you as you were already using the rc and you can check [the CHANGELOG](https://github.com/vuejs/pinia/blob/v2/packages/pinia/CHANGELOG.md) for a detailed explanation of everything that changed. Otherwise, **this guide is for you**!
## Deprecations
# Migrating from v2 to v3
+<RuleKitLink />
+
Pinia v3 is a _boring_ major release with no new features. It drops deprecated APIs and updates major dependencies. It only supports Vue 3. If you are using Vue 2, you can keep using v2. If you need help, [book help with Pinia's author](https://cal.com/posva/consultancy).
For most users, the migration should require **no change**. This guide is here to help you in case you encounter any issues.
How you choose to restructure your Vuex modules into Pinia stores is entirely up to you, but here is one suggestion:
+<RuleKitLink />
+
```bash
# Vuex example (assuming namespaced modules)
src
- ⚠️ [mapGetters](../core-concepts/getters.md#without-setup) (just for migration convenience, use `mapState()` instead)
- [mapActions](../core-concepts/actions.md#without-setup)
+<RuleKitLink />
+
## Giving access to the whole store
If you need to access pretty much everything from the store, it might be too much to map every single property of the store... Instead you can get access to the whole store with `mapStores()`:
Depending on what or how you are testing, we need to take care of these three things differently.
+<RuleKitLink />
+
## Unit testing a store
To unit test a store, the most important part is creating a `pinia` instance:
# VS Code Snippets
+<RuleKitLink />
+
These are some snippets that I use in VS Code to make my life easier.
Manage user snippets with <kbd>⇧ Shift</kbd>+<kbd>⌘ Command</kbd>+<kbd>P</kbd> / <kbd>⇧ Shift</kbd>+<kbd>⌃ Control</kbd>+<kbd>P</kbd> and then `Snippets: Configure User Snippets`.
})
```
+<RuleKitLink />
+
Like [getters](./getters.md), actions get access to the _whole store instance_ through `this` with **full typing (and autocompletion ✨) support**. **Unlike getters, `actions` can be asynchronous**, you can `await` inside of actions any API call or even other actions! Here is an example using [Mande](https://github.com/posva/mande). Note the library you use doesn't matter as long as you get a `Promise`. You could even use the native `fetch` function (browser only):
```js
})
```
+<RuleKitLink />
+
Most of the time, getters will only rely on the state. However, they might need to use other getters. Because of this, we can get access to the _whole store instance_ through `this` when defining a regular function **but it is necessary to define the type of the return type (in TypeScript)**. This is due to a known limitation in TypeScript and **doesn't affect getters defined with an arrow function nor getters not using `this`**:
```ts
`defineStore()` accepts two distinct values for its second argument: a Setup function or an Options object.
+<RuleKitLink />
+
## Option Stores
Similar to Vue's Options API, we can also pass an Options Object with `state`, `actions`, and `getters` properties.
Behind the scenes, `useStore()` _injects_ the `pinia` instance you gave to your `app`. This means that if the `pinia` instance cannot be automatically injected, you have to manually provide it to the `useStore()` function.
You can solve this differently depending on the kind of application you are writing.
+<RuleKitLink />
+
## Single Page Applications
If you are not doing any SSR (Server Side Rendering), any call of `useStore()` after installing the pinia plugin with `app.use(pinia)` will work:
- Implement side effects like [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)
- Apply **only** to specific stores
+<RuleKitLink />
+
Plugins are added to the pinia instance with `pinia.use()`. The simplest example is adding a static property to all stores by returning an object:
```js
:::
+<RuleKitLink />
+
## TypeScript
You don't need to do much in order to make your state compatible with TS: make sure [`strict`](https://www.typescriptlang.org/tsconfig#strict), or at the very least, [`noImplicitThis`](https://www.typescriptlang.org/tsconfig#noImplicitThis), is enabled and Pinia will infer the type of your state automatically! However, there are a few cases where you should give it a hand with some casting:
A Store (like Pinia) is an entity holding state and business logic that isn't bound to your Component tree. In other words, **it hosts global state**. It's a bit like a component that is always there and that everybody can read off and write to. It has **three concepts**, the [state](./core-concepts/state.md), [getters](./core-concepts/getters.md) and [actions](./core-concepts/actions.md) and it's safe to assume these concepts are the equivalent of `data`, `computed` and `methods` in components.
+<RuleKitLink />
+
## When should I use a Store
A store should contain data that can be accessed throughout your application. This includes data that is used in many places, e.g. User information that is displayed in the navbar, as well as data that needs to be preserved through pages, e.g. a very complicated multi-step form.
- theme: alt
text: Demo
link: https://stackblitz.com/github/piniajs/example-vue-3-vite
+ - theme: cta rulekit
+ text: RuleKit
+ link: https://rulekit.dev?from=vuerouter
- theme: cta mastering-pinia
text: ' '
link: https://masteringpinia.com
If you still have doubts, check out [the **official** Mastering Pinia course](https://masteringpinia.com). In the beginning we cover how to build our own `defineStore()` function and then we move to the official Pinia API.
+<RuleKitLink />
+
<VueMasteryLogoLink for="pinia-cheat-sheet">
</VueMasteryLogoLink>
--- /dev/null
+<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M335 694L353.947 697.225V737L335 733.775V694Z" fill="currentColor"/>
+ <path d="M355 538.234V673L335 669.766V536.078L355 538.234Z" fill="currentColor"/>
+ <path d="M259.255 329.5L313.424 338.585V414.78L374.576 425.512V350.39L422.5 359.457L422.529 391.816L399.251 388.374V443.756L375.649 440.537V460.314L313.424 449.576V430.878L287.675 426.585L286.602 367.561L259.255 364V329.5Z" fill="currentColor"/>
+ <path d="M398.897 113.5L647.031 158.597V199L676.034 205.5V276L836.085 304.623L896.239 362.605V498.968L873.681 516.147V778.5L914.5 792.095L755.522 914.5L180.84 802.832L130.354 738.409V472.125L103.5 457.092V336.835L164.728 270.264L291.48 205.5L321.557 211V176.85L350.56 165.5V139L398.897 113.5ZM379.562 148.933V184L350.56 182.218L349.485 259.527L379.562 263.822V184L582.581 218.725V300.328L622.325 307V224.094L598.693 220.873V188.661L379.562 148.933ZM433.271 218.725V234.831L561.097 257.379V240.2L433.271 218.725ZM291.48 234.831L223.807 272.412L740.484 364.752L802.786 325.024L673.885 302.476L622.325 330L561.097 319V282L433.271 259.527L389.23 285.296L321.557 275V240.2L291.48 234.831ZM180.84 288.517L128.206 343.277V440.537L233.475 461.387L232.401 360.457L259.255 364V446L284.103 449.576V476.42L311.889 480.714V750L373.117 762L374.191 691.165V493.599L399.251 497V472.125L422.5 476.42L422.529 391.816L449.383 396.964V500L543.911 516V414.143L571.839 418.438V388.374L624.474 396.964V423.807L652.402 428V534.5L778.08 551.5V443.756L731 392.244L180.84 288.517ZM831.789 336.835L757.671 383.005L796.341 423.807L871.533 374.416L831.789 336.835ZM807.083 445.281V529.032L871.533 486.083V404.48L807.083 445.281ZM571.839 449.576V521.516L587 524.5V592L606.213 595.603V527.5L624.474 531V458.5L571.839 449.576ZM155.06 472.125V729.5L191.5 778.5L713 880.5L754.448 853.298V579.497L635.215 560.17V601L682.479 609.562V649.29L663.144 647V682.575L682.479 684.723L683.5 814.5L652.402 808.201V839L543.911 819.5V788.874L511.685 783.505V654.5L532.095 658.5V623.52L511.685 620.299V578.424L557.875 585.94V545.138L422.5 521.516L402.12 538.234V654.658V766.326L373.117 762V791.021L311.889 778.5V750L285.035 744.851V512.926L264.5 493.599L155.06 472.125ZM778.08 579.497L780.228 833.971L847.901 781.358V538.234L778.08 579.497ZM561.097 627.5V664.5L543.911 661V788.874L565.394 793.169L567 669L584.729 672V632.5L561.097 627.5ZM611.583 639.626V676.5L628.77 679V802.832L652.402 808.201V682.575L635.215 680.428V643L611.583 639.626Z" fill="currentColor"/>
+</svg>
\ No newline at end of file
</script>
```
+<RuleKitLink />
+
## Using the store outside of `setup()`
If you need to use the store somewhere else, you need to pass the `pinia` instance [that was passed to the app](../getting-started.md#installation) to the `useStore()` function call:
Using Pinia with [Nuxt](https://nuxt.com/) is easier since Nuxt takes care of a lot of things when it comes to _server side rendering_. For instance, **you don't need to care about serialization nor XSS attacks**. Pinia supports Nuxt Bridge and Nuxt 3. For bare Nuxt 2 support, [see below](#nuxt-2-without-bridge).
+<RuleKitLink />
+
## Installation
```bash
# 处理组合式函数 %{#dealing-with-composables}%
+<RuleKitLink />
+
[组合式函数](https://cn.vuejs.org/guide/reusability/composables.html#composables)是利用 Vue 组合式 API 来封装和复用有状态逻辑的函数。无论你是自己写,还是使用[外部库](https://vueuse.org/),或者两者都有,你都可以在 pinia store 中充分发挥组合式函数的力量。
## Option Stores %{#option-stores}%
# 组合式 Store %{#composing-stores}%
+<RuleKitLink />
+
组合式 store 是可以相互使用,Pinia 当然也支持它。但有一个规则需要遵循:
如果**两个或更多的 store 相互使用**,它们不可以通过 _getters_ 或 _actions_ 创建一个无限循环。它们也不可以**同时**在它们的 setup 函数中直接互相读取对方的 state:
# HMR (Hot Module Replacement) %{#hmr-hot-module-replacement}%
+<RuleKitLink />
+
Pinia 支持热更新,所以你可以编辑你的 store,并直接在你的应用中与它们互动,而不需要重新加载页面,允许你保持当前的 state、并添加甚至删除 state、action 和 getter。
目前,只有 [Vite](https://cn.vitejs.dev/guide/api-hmr#hmr-api) 被官方支持,不过任何实现 `import.meta.hot` 规范的构建工具都应该能正常工作。(例外的是,[webpack](https://webpack.js.org/api/module-variables/#importmetawebpackhot) 似乎使用的是 `import.meta.webpackHot` 而不是 `import.meta.hot` )
# 手册 %{#cookbook}%
+<RuleKitLink />
+
- [从 Vuex ≤4 迁移](./migration-vuex.md)。用于转换 Vuex ≤4 项目的迁移指南。
- [HMR](./hot-module-replacement.md):如何激活热更新并改善开发者体验。
- [测试 Stores (WIP)](./testing.md): 如何对 Store 进行单元测试并在组件单元测试中模拟它们。
# 从 0.x (v1) 迁移至 v2 %{#migrating-from-0-x-v1-to-v2}%
+<RuleKitLink />
+
从 `2.0.0-rc.4` 版本开始,pinia 同时支持 Vue 2 和 Vue 3!这意味着,v2 版本的所有更新,将会让 Vue 2 和 Vue 3 的用户都受益。如果你使用的是 Vue 3,这对你来说没有任何改变,因为你已经在使用 rc 版本,你可以查看[发布日志](https://github.com/vuejs/pinia/blob/v2/packages/pinia/CHANGELOG.md)来了解所有更新的详细解释。如果你使用的不是 Vue 3,**那这个指南是为你准备的**!
## 弃用 %{#deprecations}%
# 从 Vuex ≤4 迁移 %{#migrating-from-vuex-≤4}%
+<RuleKitLink />
+
虽然 Vuex 和 Pinia store 的结构不同,但很多逻辑都可以复用。本指南的作用是帮助你完成迁移,并指出一些可能出现的常见问题。
## 准备 %{#preparation}%
# 不使用 `setup()` 的用法 %{#usage-without-setup}%
+<RuleKitLink />
+
即使你没有使用组合式 API,也可以使用 Pinia(如果你使用 Vue 2,你仍然需要安装 `@vue/composition-api` 插件)。虽然我们推荐你试着学习一下组合式 API,但对你和你的团队来说目前可能还不是时候,你可能正在迁移一个应用,或者有其他原因。你可以试试下面几个函数:
- [mapStores](#giving-access-to-the-whole-store)
# store 测试 %{#testing-stores}%
+<RuleKitLink />
+
<MasteringPiniaLink
href="https://play.gumlet.io/embed/65f9a9c10bfab01f414c25dc"
title="Watch a free video of Mastering Pinia about testing stores"
# VS Code 代码片段
+<RuleKitLink />
+
有一些代码片段可以让你在 VS Code 中更轻松地使用 Pinia。
通过 <kbd>⇧</kbd> <kbd>⌘</kbd> <kbd>P</kbd> / <kbd>⇧</kbd> <kbd>⌃</kbd> <kbd>P</kbd> 然后输入 `Snippets: Configure User Snippets` 就可以管理用户代码片段。
# Action %{#actions}%
+<RuleKitLink />
+
<!-- <VueSchoolLink
href="https://vueschool.io/lessons/synchronous-and-asynchronous-actions-in-pinia"
title="Learn all about actions in Pinia"
# Getter %{#getters}%
+<RuleKitLink />
+
<!-- <VueSchoolLink
href="https://vueschool.io/lessons/getters-in-pinia"
title="Learn all about getters in Pinia"
# 定义 Store %{#defining-a-store}%
+<RuleKitLink />
+
<!-- <VueSchoolLink
href="https://vueschool.io/lessons/define-your-first-pinia-store"
title="Learn how to define and use stores in Pinia"
# 在组件外使用 store %{#using-a-store-outside-of-a-component}%
+<RuleKitLink />
+
<MasteringPiniaLink
href="https://play.gumlet.io/embed/651ed1ec4c2f339c6860fd06"
mp-link="https://masteringpinia.com/lessons/how-does-usestore-work"
# 插件 %{#plugins}%
+<RuleKitLink />
+
<MasteringPiniaLink
href="https://masteringpinia.com/lessons/What-is-a-pinia-plugin"
title="Learn all about Pinia plugins"
# State %{#state}%
+<RuleKitLink />
+
<!-- <VueSchoolLink
href="https://vueschool.io/lessons/access-state-from-a-pinia-store"
title="Learn all about state in Pinia"
# 开始
+<RuleKitLink />
+
## 安装 %{#installation}%
<VueMasteryLogoLink for="pinia-cheat-sheet">
- theme: alt
text: Demo 演示
link: https://stackblitz.com/github/piniajs/example-vue-3-vite
+ - theme: cta rulekit
+ text: RuleKit
+ link: https://rulekit.dev?from=vuerouter
- theme: cta mastering-pinia
text: ' '
link: https://masteringpinia.com
如果你仍然有疑问,请查看[**官方**的 Mastering Pinia 课程](https://masteringpinia.com)。在一开始,我们会介绍如何创建自己的 `defineStore()` 函数,然后我们会转向官方的 Pinia API。
+<RuleKitLink />
+
<VueMasteryLogoLink for="pinia-cheat-sheet">
</VueMasteryLogoLink>
# 服务端渲染 (SSR) %{#server-side-rendering-ssr}%
+<RuleKitLink />
+
<MasteringPiniaLink
href="https://masteringpinia.com/lessons/ssr-friendly-state"
title="Learn about SSR best practices"
搭配 [Nuxt](https://nuxt.com/) 的 Pinia 更易用,因为 Nuxt 处理了很多与**服务器端渲染**有关的事情。例如,**你不需要关心序列化或 XSS 攻击**。Pinia 既支持 Nuxt Bridge 和 Nuxt 3,也支持纯 Nuxt 2,[见下文](#nuxt-2-without-bridge)。
+<RuleKitLink />
+
## 安装 %{#installation}%
```bash