shldhee / auth-vue3-ts

0 stars 0 forks source link

pinia #6

Open shldhee opened 2 years ago

shldhee commented 2 years ago

https://pinia.vuejs.org/getting-started.html

shldhee commented 2 years ago

https://dev.to/carlomigueldy/getting-started-with-vue-3-pinia-store-typescript-by-building-a-grocery-list-app-19km

shldhee commented 2 years ago

image

shldhee commented 2 years ago

install

npm install pinia
vue-cli 사용시
vue add vue-cli-plugin-pinia

setting

// app.ts
import { createPinia } from 'pinia'
app.use(createPinia())

import { createPinia } from 'pinia'
createApp(App)
  .use(createPinia())
  .mount("#app");

What is Store?

Defining a Store

// store/main.ts
import { defineStore } from 'pinia'

// useStore could be anything like useUser, useCart
// the first argument is a unique id of the store across your application
export const useStore = defineStore('main', {
  // other options...
})

store 사용

import { useStore } from '@/stores/counter'

export default {
  setup() {
    const store = useStore()

    return {
      // you can return the whole store instance to use it in the template
      store,
    }
  },
}

// 작동하지 않는다. 반응성을 깨뜨린다.
    // ❌ This won't work because it breaks reactivity
    // it's the same as destructuring from `props`
 const { name, doubleCount } = store
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import { generateFakeData, Item } from "./models/item.model";
import { useMainStore } from "./store/index";
export default defineComponent({
  name: "App",
  setup() {
    const items = ref<Item[]>([]);
    const mainStore = useMainStore();
    onMounted(() => {
      items.value = mainStore.items;
    });
    function createItem() {
      mainStore.createNewItem(generateFakeData());
    }
    function deleteItem(id: string) {
      mainStore.deleteItem(id);
    }
    function updateItem(id: string) {
      mainStore.updateItem(id, generateFakeData());
    }
    return {
      items,
      createItem,
      deleteItem,
      updateItem,
    };
  },
});
</script>
shldhee commented 2 years ago

store 구조분할을 사용할땐 state만 사용할때 actions은 안된다

mport { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const store = useStore()
    // `name` and `doubleCount` are reactive refs
    // This will also create refs for properties added by plugins
    // but skip any action or non reactive (non ref/reactive) property
    const { name, doubleCount } = storeToRefs(store)

    return {
      name,
      doubleCount
    }
  },
})

state 상태 정의하기

import { defineStore } from 'pinia'

const useStore = defineStore('storeId', {
  // arrow function recommended for full type inference
  state: () => {
    return {
      // all these properties will have their type inferred automatically
      counter: 0,
      name: 'Eduardo',
      isAdmin: true,
    }
  },
})

state 관리

state 접근(읽고 쓰기)

const store = useStore()
store.counter++

state 리셋(초기값으로)

const store = useStore()
store.$reset()

state mutate 여러개

store.$patch({
  counter: store.counter + 1;
  name: 'Abalam',

위와 같이 하면 모든 컬렉션 수정할때 비용이 많이 든다. 아래처럼 함수로 한다.

cartStore.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})

state 구독

cartStore.$subscribe((mutation, state) => {
  // import { MutationType } from 'pinia'
  mutation.type // 'direct' | 'patch object' | 'patch function'
  // same as cartStore.$id
  mutation.storeId // 'cart'
  // only available with mutation.type === 'patch object'
  mutation.payload // patch object passed to cartStore.$patch()

  // persist the whole state to the local storage whenever it changes
  localStorage.setItem('cart', JSON.stringify(state))
})
shldhee commented 2 years ago

Getters

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
})

다른 getters 에 접근할때

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    // automatically infers the return type as a number
    doubleCount(state) {
      return state.counter * 2
    },
    // the return type **must** be explicitly set
    doublePlusOne(): number {
      // autocompletion and typings for the whole store ✨
      return this.counter * 2 + 1
//     return this.doubleCount + 1
    },
  },
})

getters에 매개변수 전달하기

export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})

<script>
export default {
  setup() {
    const store = useStore()

    return { getUserById: store.getUserById }
  },
}
</script>

<template>
User 2: {{ getUserById(2) }}
</template>
export const useStore = defineStore('main', {
  getters: {
    getActiveUserById(state) {
      const activeUsers = state.users.filter((user) => user.active)
      return (userId) => activeUsers.find((user) => user.id === userId)
    },
  },
})

다른 스토어 getters 접근

import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

setup() 과 함께 사용할때

export default {
  setup() {
    const store = useStore()

    store.counter = 3
    store.doubleCount // 6
  },
}
shldhee commented 2 years ago

Actions

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  actions: {
    increment() {
      this.counter++
    },
    randomizeCounter() {
      this.counter = Math.round(100 * Math.random())
    },
  },
})
import { mande } from 'mande' // fetch를 쉽게

const api = mande('/api/users')

export const useUsers = defineStore('users', {
  state: () => ({
    userData: null,
    // ...
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        showTooltip(`Welcome back ${this.userData.name}!`)
      } catch (error) {
        showTooltip(error)
        // let the form component display the error
        return error
      }
    },
  },
})

action 사용하기

export default defineComponent({
  setup() {
    const main = useMainStore()
    // call the action as a method of the store
    main.randomizeCounter()

    return {}
  },
})

다른 스토어 액션 접근

import { useAuthStore } from './auth-store'

export const useSettingsStore = defineStore('settings', {
  state: () => ({
    // ...
  }),
  actions: {
    async fetchUserPreferences(preferences) {
      const auth = useAuthStore()
      if (auth.isAuthenticated) {
        this.preferences = await fetchPreferences()
      } else {
        throw new Error('User must be authenticated')
      }
    },
  },
})

setup과 사용

export default {
  setup() {
    const store = useStore()

    store.randomizeCounter()
  },
}

action subscribe

Here is an example that logs before running actions and after they resolve/reject.

다음은 작업을 실행하기 전과 해결/거부한 후 기록하는 예입니다.

const unsubscribe = someStore.$onAction(
  ({
    name, // name of the action
    store, // store instance, same as `someStore`
    args, // array of parameters passed to the action
    after, // hook after the action returns or resolves
    onError, // hook if the action throws or rejects
  }) => {
    // a shared variable for this specific action call
    const startTime = Date.now()
    // this will trigger before an action on `store` is executed
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // this will trigger if the action succeeds and after it has fully run.
    // it waits for any returned promised
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // this will trigger if the action throws or returns a promise that rejects
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// manually remove the listener
unsubscribe()