Thuta Learning
ရှာဖွေရန်
ExercisesWeb Developmentbeginner

Practice: Components, Router & State Challenge

စိတ်လျှော့ပါ။ ဒီခန်းကို စာအုပ်လိုမဟုတ်ဘဲ စကားပြောသလိုပဲ၊ နားလည်လွယ်အောင် ရှင်းပါမယ်။

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Practice: Components, Router & State Challenge ကို ကိုယ်တိုင် လေ့ကျင့်ကြည့်မယ်
  • သင်ခဲ့ပြီးသား skill တွေကို practice လုပ်ပြီး ခိုင်မာအောင်လုပ်မယ်
  • အမှားရှာ၊ ပြင်တတ်၊ ကိုယ်တိုင် check လုပ်တတ်မယ်

ခဏလေး ဒီလိုပဲ စဉ်းစားကြည့်

ဒီ lesson က Intermediate/Advanced chapter မှာ လေ့လာခဲ့တဲ့ component communication, composables, routing, state management concept တွေကို တစ်ခါတည်း ပေါင်းစပ်သုံးကြည့်ရန် ရည်ရွယ်ထားတယ်။ Task တွေက production app တစ်ခုမှာ အမှန်တကယ် ကြုံရနိုင်တဲ့ scenario နဲ့ ဆင်တူအောင် ပြင်ဆင်ထားပါတယ်။ Concept အသစ် သင်ပေးတာ မဟုတ်ဘဲ ရှိပြီးသား knowledge ကို ပေါင်းစပ်အသုံးချနိုင်မလား စစ်ဆေးတာဖြစ်တယ်။ Task 1 ကို ပြီးမှ Task 2၊ 3 ကို ဆက်လုပ်ရင် logic ချိတ်ဆက်ပုံ ပိုမြင်ရလိမ့်မယ်။

လေ့ကျင့်ခန်းများ

Task 1: parent component က 'items' array ကို props အနေနဲ့ child list component ဆီ ပို့ပြီး child ထဲက delete button ကို click လုပ်ရင် emit('delete', id) ဖြင့် parent ကို item ဖျက်ဖို့ event ပြန်ပို့ပါ။ Task 2: useCounter() ဆိုတဲ့ composable တစ်ခု ရေးပြီး count, increment, decrement ကို return လုပ်ကာ component နှစ်ခုမှာ တစ်ချိန်တည်း import သုံးပြီး state က component တစ်ခုချင်းစီအတွက် သီးခြားစီ ဖြစ်နေကြောင်း သက်သေပြပါ။ Task 3: Pinia store 'useCartStore' တစ်ခုတည်ဆောက်ပြီး addItem action နဲ့ total price ကို getter အနေနဲ့ ရေးကာ Vue Router ဖြင့် route ၂ ခု ('/cart' နှင့် '/checkout') ကြားမှာ navigate လုပ်ရင်တောင် store data မပျောက်ဘဲ ရှိနေကြောင်း စစ်ဆေးပါ။

Code နမူနာ

javascript
// useCounter.js (Task 2)
import { ref } from 'vue'

export function useCounter(start = 0) {
  const count = ref(start)
  const increment = () => count.value++
  const decrement = () => count.value--
  return { count, increment, decrement }
}

// stores/cart.js (Task 3)
import { defineStore } from 'pinia'

export const useCartStore = defineStore('cart', {
  state: () => ({ items: [] }),
  getters: {
    total: (state) => state.items.reduce((sum, i) => sum + i.price, 0)
  },
  actions: {
    addItem(item) {
      this.items.push(item)
    }
  }
})

// ListItem.vue child (Task 1)
// props: { item: Object }
// emits: ['delete']
// template button: @click="$emit('delete', item.id)"
You should see
Delete button ကို child မှာနှိပ်ရင် parent ရဲ့ items array ထဲက item ပျောက်သွားပြီး၊ composable ကိုသုံးထားတဲ့ component နှစ်ခုစီရဲ့ counter တွေက တစ်ခုနဲ့တစ်ခု မထိခိုက်ဘဲ သီးခြားစီ count လုပ်ကာ၊ cart page ကနေ checkout page ကို navigate လုပ်ရင်တောင် cart total price က မပျောက်ဘဲ ရှိနေရမည်။

၅ မိနစ် စမ်းကြည့်

Task 2 ကို component နှစ်ခု (CounterA.vue, CounterB.vue) ဖန်တီးပြီး useCounter() ကို import တူတူသုံးကာ button နှိပ်တဲ့အခါ state တစ်ခုနဲ့တစ်ခု မသက်ဆိုင်ကြောင်း console.log နဲ့ ၅ မိနစ်အတွင်း သက်သေပြကြည့်ပါ။

သတိလေးတစ်ချက်

Pinia store ထဲက state ကို destructure လုပ်ချင်ရင် storeToRefs() ကို မဖြစ်မနေသုံးပါ၊ မဟုတ်ရင် reactivity link ပြတ်သွားပြီး UI update မလုပ်တော့ပါဘူး။

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • child component ကနေ props (item) ကို တိုက်ရိုက် mutate လုပ်မိပြီး parent state နဲ့ sync မကိုက်တော့တဲ့ error ဖြစ်ခြင်း
  • Pinia store ကို component ထဲမှာ တိုက်ရိုက် reactive object destructure (const { items } = store) လုပ်လိုက်ပြီး reactivity ပျက်သွားခြင်း

အခု ကိုယ်တိုင် စမ်းကြည့်

Task 2 ကို component နှစ်ခု (CounterA.vue, CounterB.vue) ဖန်တီးပြီး useCounter() ကို import တူတူသုံးကာ button နှိပ်တဲ့အခါ state တစ်ခုနဲ့တစ်ခု မသက်ဆိုင်ကြောင်း console.log နဲ့ ၅ မိနစ်အတွင်း သက်သေပြကြည့်ပါ။

You'll know it worked when: Delete button ကို child မှာနှိပ်ရင် parent ရဲ့ items array ထဲက item ပျောက်သွားပြီး၊ composable ကိုသုံးထားတဲ့ component နှစ်ခုစီရဲ့ counter တွေက တစ်ခုနဲ့တစ်ခု မထိခိုက်ဘဲ သီးခြားစီ count လုပ်ကာ၊ cart page ကနေ checkout page ကို navigate လုပ်ရင်တောင် cart total price က မပျောက်ဘဲ ရှိနေရမည်။

Practice: Components, Router & State Challenge | Thuta Learning