]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
docs: add readme
authorEduardo San Martin Morote <posva13@gmail.com>
Tue, 26 Nov 2019 22:33:43 +0000 (23:33 +0100)
committerEduardo San Martin Morote <posva13@gmail.com>
Tue, 26 Nov 2019 22:33:43 +0000 (23:33 +0100)
README.md

index 17d96152ad8c8d37620af48c40683986dc1070f5..7e81e0c5a8be1e5cddf78d7dc4cae1d8d1a09896 100644 (file)
--- a/README.md
+++ b/README.md
 # pinia [![Build Status](https://badgen.net/circleci/github/posva/pinia/master)](https://circleci.com/gh/posva/pinia) [![npm package](https://badgen.net/npm/v/pinia)](https://www.npmjs.com/package/pinia) [![coverage](https://badgen.net/codecov/c/github/posva/pinia/master)](https://codecov.io/github/posva/pinia) [![thanks](https://badgen.net/badge/thanks/♥/pink)](https://github.com/posva/thanks)
 
-> Some awesome description
+> 🍍Type Safe Modular and lightweight (but **Experimental**) Store for Vue based on the composition api
 
 Demo (TODO link)
 
+⚠⚠⚠ This project is experimental, it's an exploration of whan a _Store_ could be like using [the composition api](https://vue-composition-api-rfc.netlify.com). It works for Vue 2 by using the [official library](https://github.com/vuejs/composition-api).
+
+What I want is to maybe inspire others to think about ways to improve Vuex.
+
+There are the core principles that I try to achieve with this experiment:
+
+- Flat modular structure 🍍 No nesting, only stores, compose them as needed
+- Light layer on top of Vue 💨 keep it under 1kg gzip
+- Only `state` and `getters` 👐 `patch` is the new _mutation_
+- Actions are just functions ⚗️ Group your business there
+- import what you need, let webpack code split 📦 And you won't need modules!
+- SSR support ⚙️
+- DevTools support 💻 Which is crucial to make this enjoyable
+
+## FAQ
+
+A few notes about the project and possible questions:
+
+**Q**: _Does this replace Vuex, is it its successor?_
+**A**: No, or at least that's not the main intention
+
+**Q**: _What about dynamic modules?_
+**A**: Dynamic modules are not type safe, so instead [we allow creating different stores](#TODO) that can be imported anywhere
+
+## Roadmap / Ideas
+
+- [ ] List Getters on DevTools
+- [ ] Nuxt Module
+- [ ] Automatic fresh store on Server Side?
+- [ ] Flag to remove devtools support (for very light production apps)
+- [ ] Allow grouping stores together into a similar structure and allow defining new getters
+
 ## Installation
 
 ```sh
-npm install lib-boilerplate
+yarn add pinia
+# or with npm
+npm install pinia
 ```
 
 ## Usage
 
-## API
+### Creating a Store
+
+You can create as many stores as you want, and they should each exist in isolated files:
+
+```ts
+import { createStore } from 'pinia'
+
+export const useMainStore = createStore(
+  // name of the store
+  // it is used in devtools and allows restoring state
+  'main',
+  // a function that returns a fresh state
+  () => ({
+    counter: 0,
+    name: 'Eduardo',
+  }),
+  // optional getters
+  {
+    doubleCount: state => state.counter * 2,
+  }
+)
+```
+
+`createStore` returns a function that has to be called to get access to the store:
+
+```ts
+import { useMainStore } from '@/stores/main'
+
+export default createComponent({
+  setup() {
+    const main = useMainStore()
+
+    return {
+      // gives access to the whole store
+      main,
+      // gives access to the state
+      state: main.state,
+      // gives access to specific getter,
+    }
+  },
+})
+```
+
+**There is one important rule for this to work**: the `useMainStore` (or any other _useStore_ function) must be called inside of deffered functions. This is to allow the Vue Composition API plugin to be installed. \*\*Never, ever call `useStore` like this:
+
+```ts
+import { useMainStore } from '@/stores/main'
+// ❌ Depending on where you do this it will fail
+// so just don't do it
+const main = useMainStore()
+
+export default createComponent({
+  setup() {
+    return {}
+  },
+})
+```
+
+Once you have access to the store, you can access the `state` through `store.state` and any getter directly on the `store` itself as a _computed_ property (from `@vue/composition-api`) (meaning you need to use `.value` to read the actual value on the JavaScript but not in the template):
+
+```ts
+export default createComponent({
+  setup() {
+    const main = useMainStore()
+    const text = main.state.name
+    const doubleCount = main.doubleCount.value // notice the `.value` at the end
+    return {}
+  },
+})
+```
+
+`state` is the result of a `ref` while every getter is the result of a `computed`. Both from `@vue/composition-api`.
+
+### Mutating the `state`
+
+To mutate the state you can either directly change something:
+
+```ts
+main.state.counter++
+```
+
+or call the method `patch` that allows you apply multiple changes at the same time with a partial `state` object:
+
+```ts
+main.patch({
+  counter; -1,
+  name: 'Abalam',
+})
+```
+
+The main difference here is that `patch` allows you to group multiple changes into one single entry in the devtools.
+
+### Replacing the `state`
+
+Simply set it to a new object;
+
+```ts
+main.state = { counter: 666, name: 'Paimon' }
+```
+
+### SSR
+
+The main part about SSR is **not sharing `state`** between requests. So we can pass `true` to `useStore` **once** when getting a new request on the server. If we follow [the SSR guide](https://ssr.vuejs.org/guide/data.html), our `createApp` should look like this:
+
+```ts
+export function createApp() {
+  // Here there could also be a router
+  const store = useStore(true)
+
+  // we can change the state now!
+  store.state.counter++
+
+  // create the app instance
+  const app = new Vue({
+    render: h => h(App),
+  })
+
+  // expose the app and the store.
+  return { app, store }
+}
+```
+
+### Actions
+
+Actions are simply function that contain business logic. As with components, they **must call `useStore`** to retrieve the store:
+
+```ts
+export async function login(user, password) {
+  const store = useUserStore()
+  const userData = await apiLogin(user, password)
+
+  store.patch({
+    name: user,
+    ...userData,
+  })
+}
+```
+
+### Composing Stores
+
+Composing stores may look hard at first glance but there is only one rule to follow really:
+
+If **multiple stores use each other** or you need to use **multiple stores** at the same time, you must create a **separate file** where you import all of them.
+
+If one store uses an other store, there is no need to create a new file, you can directly import it. Think of it as nesting.
+
+#### Shared Getters
+
+If you need to compute a value based on the `state` and/or `getters` of multiple stores, you may be able to import all the stores but one into the remaining store, but depending on how your stores are used across your application, **this would hurt your code splitting** as you importing the store that imports all others stores, would result in **one single big chunk** with all of your stores.
+To prevent this, **we follow the rule above** and we create a new file:
+
+```ts
+import { computed } from '@vue/composition-api'
+import { useUserStore } from './user'
+import { useCartStore } from './cart'
+
+export const summary = computed(() => {
+  const user = useUserStore()
+  const cart = useCartStore()
+
+  return `Hi ${user.state.name}, you have ${cart.state.list.length} items in your cart. It costs ${cart.price}.`
+})
+```
+
+#### Shared Actions
+
+When an actions needs to use multiple stores, we do the same, we create a new file:
+
+```ts
+import { useUserStore } from './user'
+import { useCartStore, emptyCart } from './cart'
+
+export async function orderCart() {
+  const user = useUserStore()
+  const cart = useCartStore()
+
+  try {
+    await apiOrderCart(user.state.token, cart.state.items)
+    emptyCart()
+  } catch (err) {
+    displayError(err)
+  }
+}
+```
 
 ## Related