]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
docs: add map helpers docs
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 9 Apr 2021 08:56:45 +0000 (10:56 +0200)
committerEduardo San Martin Morote <posva@users.noreply.github.com>
Fri, 9 Apr 2021 11:08:56 +0000 (13:08 +0200)
docs/.vitepress/config.js
docs/cookbook/options-api.md [new file with mode: 0644]
docs/core-concepts/actions.md
docs/core-concepts/getters.md
docs/core-concepts/state.md
docs/introduction.md
test-dts/mapHelpers.test-d.ts

index 9905109b8259a27a44495c17aa008e20548c5926..d8fccd30ef9024108b004462b9a3bce7334dc12a 100644 (file)
@@ -202,6 +202,10 @@ module.exports = {
               text: 'Composing Stores',
               link: '/cookbook/composing-stores.html',
             },
+            {
+              text: 'Usage without setup()',
+              link: '/cookbook/options-api.html',
+            },
           ],
         },
       ],
diff --git a/docs/cookbook/options-api.md b/docs/cookbook/options-api.md
new file mode 100644 (file)
index 0000000..ce567bb
--- /dev/null
@@ -0,0 +1,68 @@
+# Usage without `setup()`
+
+Pinia can be used even if you are not using the composition API (if you are using Vue 2, you still need to install the `@vue/composition-api` plugin though). While we recommend you to give the Composition API a try and learn it, it might not be the time for you and your team yet, you might be in the process of migrating an application, or any other reason. There are a few functions:
+
+- [mapStores](#giving-access-to-the-whole-store)
+- [mapState](../core-concepts/state.md#options-api)
+- [mapWritableState](../core-concepts/state.md#modifiable-state)
+- ⚠️ [mapGetters](../core-concepts/getters.md#options-api) (just for migration convenience, use `mapState()` instead)
+- [mapActions](../core-concepts/actions.md#options-api)
+
+## 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()`:
+
+```js
+import { mapStores } from 'pinia'
+
+// given two stores with the following ids
+const useUserStore = defineStore({ id: 'user' })
+const useCartStore = defineStore({ id: 'cart' })
+
+export default {
+  computed: {
+    // note we are not passing an array, just one store after the other
+    // each store will be accessible as its id + 'Store'
+    ...mapStores(useCartStore, useUserStore),
+    }),
+  },
+
+  methods: {
+    async buyStuff() {
+      // use them anywhere!
+      if (this.userStore.isAuthenticated()) {
+        await this.cartStore.buy()
+        this.$router.push('/purchased')
+      }
+    },
+  },
+}
+```
+
+By default, Pinia will add the `"Store"` suffix to the `id` of each store. You can customize this behavior by calling the `setMapStoreSuffix()`:
+
+```js
+import { createPinia, setMapStoreSuffix } from 'pinia'
+
+setMapStoreSuffix('') // completely remove the suffix
+setMapStoreSuffix('_store') // user_store, cart_store (it's okay, I won't judge you)
+export const pinia = createPinia()
+```
+
+## TypeScript
+
+By default, all map helpers support autocompletion and you don't need to do anything. If you call `setMapStoreSuffix()` to change the `"Store"` suffix, you will need to also add it somewhere in a TS file or your `global.d.ts` file. The most convenient place would be the same place where you call `setMapStoreSuffix()`:
+
+```ts
+import { createPinia, setMapStoreSuffix } from 'pinia'
+
+setMapStoreSuffix('') // completely remove the suffix
+export const pinia = createPinia()
+
+declare module 'pinia' {
+  export interface MapStoresCustomization {
+    // set it to the same value as above
+    suffix: ''
+  }
+}
+```
index 20915e670f1fa6a3f3f3ba57acbbfc0a535415a2..99d3cc03a2a22b428146ce07a9179d8463167d50 100644 (file)
@@ -9,6 +9,9 @@ export const useStore = defineStore({
     counter: 0,
   }),
   actions: {
+    increment() {
+      this.counter++
+    },
     randomizeCounter() {
       this.counter = Math.round(100 * Math.random())
     },
@@ -56,3 +59,35 @@ export const useSettingsStore = defineStore({
   },
 })
 ```
+
+## Usage with `setup()`
+
+You can directly call any action as a method of the store:
+
+```js
+export default {
+  setup() {
+    const store = useStore()
+
+    store.randomzieCounter()
+  },
+}
+```
+
+## Usage with options API
+
+If you are not using the composition API, and you are using `computed`, `methods`, ..., you can use the `mapActions()` helper to map actions properties as methods in your component:
+
+```js
+import { mapActions } from 'pinia'
+
+export default {
+  computed: {
+    // gives access to this.increment() inside the component
+    // same as calling from store.increment()
+    ...mapActions(useStore, ['increment'])
+    // same as above but registers it as this.myOwnName()
+    ...mapActions(useStore, { myOwnName: 'doubleCounter' }),
+  },
+}
+```
index 1b837fd6c54de8c3b9ada1382bf4da5982a36271..6ee811b88a6884d22619c7fb3712b9bb041cda00 100644 (file)
@@ -78,3 +78,40 @@ export const useStore = defineStore({
   },
 })
 ```
+
+## Usage with `setup()`
+
+You can directly access any getter as a property of the store (exactly like state properties):
+
+```js
+export default {
+  setup() {
+    const store = useStore()
+
+    store.counter = 3
+    store.doubleCount // 6
+  },
+}
+```
+
+## Options API
+
+You can use the same `mapState()` function used in the [previous section of state](./state.md#options-api) to map to getters:
+
+```js
+import { mapState } from 'pinia'
+
+export default {
+  computed: {
+    // gives access to this.doubleCounter inside the component
+    // same as reading from store.doubleCounter
+    ...mapState(useStore, ['doubleCount'])
+    // same as above but registers it as this.myOwnName
+    ...mapState(useStore, {
+      myOwnName: 'doubleCounter',
+      // you can also write a function that gets access to the store
+      double: store => store.doubleCount,
+    }),
+  },
+}
+```
index 3ca8e16697364dac51e85d74d4db950a366b45de..8fceb128a95f896ea9b16f14ce70c418c2181ee1 100644 (file)
@@ -29,9 +29,62 @@ const store = useStore()
 store.counter++
 ```
 
+### Options API
+
+If you are not using the composition API, and you are using `computed`, `methods`, ..., you can use the `mapState()` helper to map state properties as readonly computed properties:
+
+```js
+import { mapState } from 'pinia'
+
+export default {
+  computed: {
+    // gives access to this.counter inside the component
+    // same as reading from store.counter
+    ...mapState(useStore, ['counter'])
+    // same as above but registers it as this.myOwnName
+    ...mapState(useStore, {
+      myOwnName: 'counter',
+      // you can also write a function that gets access to the store
+      double: store => store.counter * 2,
+      // it can have access to `this` but it won't be typed correctly...
+      magicValue(store) {
+        return store.someGetter + this.counter + this.double
+      },
+    }),
+  },
+}
+```
+
+#### Modifiable state
+
+If you want to be able to write to these state properties (e.g. if you have a form), you can use `mapWritableState()` instead. Note you cannot pass a function like with `mapState()`:
+
+```js
+import { mapWritableState } from 'pinia'
+
+export default {
+  computed: {
+    // gives access to this.counter inside the component and allows setting it
+    // this.counter++
+    // same as reading from store.counter
+    ...mapWritableState(useStore, ['counter'])
+    // same as above but registers it as this.myOwnName
+    ...mapWritableState(useStore, {
+      myOwnName: 'counter',
+    }),
+  },
+}
+```
+
+:::tip
+You don't need `mapWritableState()` for collections like arrays unless you are replacing the whole array with `cartItems = []`, `mapState()` still allows you to call methods on your collections.
+:::
+
+## Mutating the state
+
 <!-- TODO: disable this with `strictMode` -->
 
-or call the method `$patch` that allows you apply multiple changes at the same time with a partial `state` object:
+Apart from directly changing a the store with `store.counter++`, you can also call the `$patch` method. It allows you to apply multiple changes at the same time with a partial `state` object:
 
 ```js
 store.$patch({
@@ -40,7 +93,7 @@ store.$patch({
 })
 ```
 
-The `$patch` method also accepts a function to group object mutations that are difficult to apply with an object, e.g. array mutations:
+However, some mutations are really hard or costly to apply with this syntax: any collection modification (e.g. pushing, removing, splicing an element from an array) requires you to create a new collection. Because of this, the `$patch` method also accepts a function to group this kind of mutations that are difficult to apply with a patch object:
 
 ```js
 cartStore.$patch((state) => {
@@ -60,3 +113,9 @@ You can replace the whole state of a store by setting its `$state` property to a
 ```js
 store.$state = { counter: 666, name: 'Paimon' }
 ```
+
+You can also replace the whole state of your application by changing the `state` of the `pinia` instance. This is used during [SSR for hydration](http://localhost:3000/ssr/#state-hydration).
+
+```js
+pinia.state.value = {}
+```
index 2d35876c2fdda242a6c65fe60b9c2c2b8b8f8c76..f75d9ab7948bcfd3da7e0c55a9d5dc93ba3e9677 100644 (file)
@@ -64,6 +64,8 @@ export default {
 }
 ```
 
+You will find more information about each _map helper_ in the core concepts.
+
 ## Why _Pinia_
 
 Pinia (pronounced like `/peenya/` in English) is the closest word to _piña_ (_pineapple_ in Spanish) that is a valid package name. A pineapple is in reality a group of individual flowers that join together to create a multiple fruit. Similar to stores, each one is born individually, but they are all connected at the end. It's also a delicious tropical fruit indigenous to South America.
index 8b77999268e4e68c2f3efba8ef8d14bd2297b3bf..46db81a68db2243db2b3d86976579f49b813cbba 100644 (file)
@@ -42,6 +42,9 @@ type CounterStore = ReturnType<typeof useCounter>
 
 const computedStores = mapStores(useStore, useStoreDos, useCounter)
 
+// @ts-expect-error: no array
+mapStores([useStore, useStoreDos, useCounter])
+
 expectType<{
   nameStore: () => MainStore
   dosStore: () => DosStore