Vue 02
Pinia state management
Create the root store, and pass it to app
import { createPinia } from 'pinia'
app.use(createPinia());
app.use(router);
app.mount("#app");
Pinia - STORE
A Store is an entity holding state and business logic that isn't bound to your Components.
Pinia store has three concepts: the state, getters and actions.
Store setup can be done 2 ways - similar ways to Vue's options api or composition api.
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.
Pinia - Define store
Setup Store
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useNumberStore = defineStore('number', () => {
const count = ref(0)
const doubleNumber = computed(() => count.value * 2)
const increment = () => count.value++
const incrementBy = (val: number) => count.value += val
return { count, doubleNumber, increment, incrementBy }
})
OR Option Store
import { defineStore } from "pinia";
export const useCounterStore = defineStore({
id: "counter",
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
actions: {
increment() {
this.counter++;
},
},
});
In Setup Stores:
- ref()s become state properties
- computed()s become getters
- function()s become actions
Pinia - Using store
Import and use store in your component.
<script setup lang="ts">
import { useNumberStore } from './stores/counter';
const store = useNumberStore();
store.$subscribe((mutation, state) => {
console.log(mutation, state);
console.log(state.count);
});
const changeState = () => {
store.count = -1;
}
</script>
<template>
<div>{{ store.count }}</div>
<button @click="store.increment()">+1</button>
<button @click="store.incrementBy(5)">+5</button>
<button @click="changeState()">set to -1</button>
</template>
<style scoped>
</style>
Destructing store
Use storeToRefs()
.
const store = useNumberStore();
const { count, doubleNumber } = storeToRefs(store)
Template Refs
Direct access to the underlying DOM elements.
<script setup>
import { ref, onMounted } from 'vue'
const input = ref(null)
onMounted(() => {
input.value.focus()
})
</script>
<template>
<input ref="input" />
</template>
Vue router
If needed later then npm install vue-router@4
. Or include it when creating new project.
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './assets/main.css'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
- Globally registering the RouterView and RouterLink components.
- Adding the global $router and $route properties.
- Enabling the useRouter() and useRoute() composables.
- Triggering the router to resolve the initial route.
Router component
- https://router.vuejs.org
- Main navigation between different sections in app are provided in Router component -
src/router/index.ts
- Selected component is rendered to
<RouterView />
Router
src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import OwnersEdit from '../views/owners/Edit.vue'
const routes: Array<RouteConfig> = [
{
path: '/', name: 'Home', component: Home
},
// ==================== Owners ====================
{
path: '/owners', name: 'OwnersIndex',
// lazy loading chunk
component: () => import("../views/owners/Index.vue")
},
// When props is set to true, use defineProps macro in component
{
path: '/owners/edit/:id', name: 'OwnersEdit', component: OwnersEdit, props: true
},
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
export default router;
Routing
{
path: '/test/:id', name: 'Test',
component: Test, props: true
},
-
Specify url paceholders with
propertyName
. -
Include props: true to map from url placeholders to component props.
-
Catchall with
*
Receiving propertiess
<script setup lang="ts">
const props = defineProps(['foo'])
console.log(props.foo)
</script>
or using object syntax
<script setup lang="ts">
const props = defineProps({
title: String,
likes: Number
})
</script>
RouterView
<!-- route outlet -->
<!-- component matched by the route will render here -->
<router-view></router-view>
Router - navigation
-
Declarative
<RouterLink :to="'viewpath'">
<RouterLink :to="{name:'personsedit', params: {id: id}}">Edit</RouterLink>
-
Programmatic
router.push(…)
-
Argument can be string path or a location descriptor object
router.push(‘animals’)
router.push({name: ‘animals’, params: {id: ‘5’}, query: {foo: ‘bar’}})
router.go(n)
– navigate n steps back or forward
<script setup lang="ts">
import { RouterLink, useRouter, useRoute } from 'vue-router';
const router = useRouter()
const route = useRoute()
const go = () => {
router.push({
name: 'second',
params: { id: '5' },
query: { foo: 'bar' }
});
}
</script>
<template>
Home
<RouterLink :to="'second'">To Second View</RouterLink>
<button @click="go()">second</button>
</template>
<style scoped></style>
<script setup lang="ts">
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const props = defineProps({
id: String,
})
</script>
<template>
Second: "{{ id }}" - "{{ route.query.foo }}"
</template>
<style scoped></style>
Watching route changes
<script setup>
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'
const route = useRoute()
const userData = ref()
// fetch the user information when params change
watch(
() => route.params.id,
async newId => {
userData.value = await fetchUser(newId)
}
)
</script>