Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Vue 3 Advanced Features and Pinia State Management

Tech Jun 6 2

Advanced Implementation Details

Component Name Configuration

Setting component name properties enhances debugging and tooling support:

<script setup>
// Supported in Vue 3.3+
defineOptions({
  name: 'ComponentName',
  inheritAttrs: false
})
</script>

Slot Systems and Scoped Slots

Understanding different slot types provides flexible component composition:

<template>
  <component-wrapper>
    <div>Default slot content</div>
    <template #named-slot>
      <div>Named slot implementation</div>
    </template>
    <template #scoped-slot="slotData">
      <div>Scoped slot with data: {{ slotData }}</div>
    </template>
  </component-wrapper>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import ComponentWrapper from '@/components/ComponentWrapper.vue'

export default defineComponent({
  name: 'ParentComponent',
  components: {
    ComponentWrapper
  }
})
</script>

The rendering implementation handles different slot types:

<script lang="ts">
import { defineComponent, CreateElement, VNode } from 'vue'

export default defineComponent({
  name: 'ComponentWrapper',
  render(createElement: CreateElement): VNode {
    console.log(this.$slots) // Excludes scoped slots
    console.log(this.$scopedSlots) // Supports value passing
    return createElement('div', {}, [
      this.$slots.default,
      this.$slots['named-slot'],
      this.$scopedSlots!.default!(null),
      this.$scopedSlots!['named-slot']!(null),
      this.$scopedSlots!['scoped-slot']!('scoped-data')
    ])
  }
})
</script>

Template Iteration Patterns

Different iteration methods serve distinct purposes in Vue templates:

<template>
  <div>
    <div v-for="(item, index) of itemsArray" :key="index">{{ item }}</div>
    <div v-for="(value, key) in dataObject" :key="key">{{ key }}: {{ value }}</div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'IterationExample',
  data() {
    return {
      itemsArray: ['Mammoth', 'Axe Warrior', 'Mars'],
      dataObject: {
        name: 'Ice Maiden',
        kills: 10,
        deaths: 0
      }
    }
  }
})
</script>

TypeScript Functional Components

Functional components provide lightweight alternatives for simple UI elements:

Named functional component approach:

import type { SetupContext } from 'vue'

type MessageComponentProps = {
  textContent: string
}
type EventHandlers = {
  sendText(content: string): void
}

function MessageComponent(
  props: MessageComponentProps,
  context: SetupContext<eventhandlers>
) {
  return (
    <button onClick={() => context.emit('sendText', props.textContent)}>
        {props.textContent} {' '}
    </button>
  )
}

MessageComponent.props = {
  textContent: {
    type: String,
    required: true
  }
}
MessageComponent.emits = {
  sendText: (value: unknown) => typeof value === 'string'
}
MessageComponent.inheritAttrs = false
MessageComponent.displayName = 'MessageComponent'
</eventhandlers>

Anonymous funcitonal component pattern:

import type { FunctionalComponent } from 'vue'

const MessageComponent: FunctionalComponent<messagecomponentprops eventhandlers=""> = (
  props,
  context
) => {
  return (
    <button onClick={() => context.emit('sendText', props.textContent)}>
        {props.textContent} {' '}
    </button>
  )
}
</messagecomponentprops>

Pinia State Management

Application Initialization

Main application setup integrates Pinia for global state management:

import App from './App.vue'
import router from './router'
import { createApp } from 'vue'
import { createPinia } from 'pinia'

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

Store Structure Organization

Store definitions encapsulate state, getters, and actions in organized modules:

import { defineStore } from 'pinia';

interface ProductItem {
    id: number;
    title: string;
    quantity: number;
}
interface ShoppingCartState {
    customerName: string;
    customerAge: number;
    productList: ProductItem[];
}

export const useShoppingStore = defineStore("shopping-cart", {
    state: (): ShoppingCartState => {
        return {
            customerName: 'Xiao Meng', 
            customerAge: 18,
            productList: [{id: 1, title: 'Mobile Phone', quantity: 1}]
        }
    },

    getters: {
         userCategory: (state) => { 
            console.log('getter context:', this) 
            return state.customerAge < 18 ? 'Minor' : 'Adult';
        },

        getProductById (state) {
            console.log('getter access:', state.customerName, this.customerName);
            return (id: number) => this.productList.find(item => item.id == id);
        }
    },

    actions: {
        addProduct (product: ProductItem) {
            if (product.quantity) product.quantity = product.quantity / 1;
           const existingItem = this.productList.find(item => item.id == product.id);
           if (existingItem)  {
               existingItem.quantity += product.quantity; 
           } else {
               this.productList.push(product);
           }
        },
    }
})

Alternative store definition using setup syntax:

import { defineStore } from "pinia";
import { ref, computed } from 'vue';

export const useNumberStore = defineStore('number-counter', () => {
    const currentCount = ref(0);
    const userName = ref('Zhang San');

    const doubledValue = computed(() => currentCount.value * 2);

    function incrementCount() {
        currentCount.value++;
    }

    return { 
        currentCount,
        doubledValue,
        incrementCount
    }
})

View Integration and Usage

Components interact with stores through various methods and patterns:

<script setup lang="ts">
import { useShoppingStore } from '@/stores/shopping';
import { useNumberStore } from '@/stores/number';

import { storeToRefs } from 'pinia';
import { ref } from 'vue';

const shoppingStore = useShoppingStore();
const numberStore = useNumberStore();

const { customerAge } = storeToRefs(shoppingStore);

function updateCustomerAge() {
  shoppingStore.$patch((state) => {
    state.customerName = 'Xiao Fei';
    state.customerAge = 35;
    state.productList.push({id: state.productList.length+1, title: 'Computer', quantity: 2})
  })
}

function resetCustomerData() {
  shoppingStore.$reset();
}

shoppingStore.$subscribe((mutation, state) => {
  console.log('State monitoring', mutation.storeId, state.customerName)
  localStorage.setItem('shopping-cart', JSON.stringify(state));
})

const productId = ref<number>(1);
const productName = ref<string>('');
const productQuantity = ref<number>(1);

function addToCart() {
  const product = {id: productId.value, title: productName.value, quantity: productQuantity.value};
  shoppingStore.addProduct(product);
}

</script>

<template>
  <div>
    <p>Customer: {{ shoppingStore.customerName }}</p>
    <p>Age: {{ customerAge }}</p>
    <p>Products:</p>
    <ul>
      <li v-for="(item, index) in shoppingStore.productList" :key="index">
        ID: {{ item.id }},Title: {{ item.title }},Quantity: {{ item.quantity }}
      </li>
    </ul>
    <input v-model="productId" placeholder="Product ID">  
    <input v-model="productName" placeholder="Product Title">  
    <input v-model="productQuantity" placeholder="Quantity">  
    <button @click="addToCart">Add to Cart</button>
    <br>
    <br>
    <button @click="updateCustomerAge">Update Age</button>
    <br><br>
    <button @click="resetCustomerData">Reset Data</button>
    <p>Category: {{ shoppingStore.userCategory }}</p>
    <p>Product Lookup: {{ shoppingStore.getProductById(1) }}</p>
    <h3>Setup Store Example</h3>
    <p>Count: {{ numberStore.currentCount }} , {{ numberStore.doubledValue }}</p>
    <button @click="numberStore.incrementCount">Increment</button>
  </div>
</template>

Tags: Vue3

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.