Skip to content
GitHub

Flux နှင့် Redux (State Management)

Flux ဆိုတာ ဘာလဲ? (ဘဏ် ဥပမာ)

Section titled “Flux ဆိုတာ ဘာလဲ? (ဘဏ် ဥပမာ)”

Flux ဆိုတာ Facebook က တီထွင်ခဲ့တဲ့ Pattern တစ်ခုပါ။ သူ့ရဲ့ အဓိက သဘောတရားကတော့ “One Way Traffic” (Data တွေ တစ်လမ်းမောင်းပဲ သွားရမယ်) ဆိုတာပါပဲ။ ဒါကို နားလည်ဖို့ ဘဏ်တစ်ခုကို မြင်ယောင်ကြည့်ပါ။

flux architecture
  1. View (Customer): ငွေထုတ်ချင်တယ်။ (Button ကို နှိပ်လိုက်တယ်)
  2. Action (Withdrawal Slip): “ဒေါ်လာ ၁၀ ထုတ်မည်” ဆိုတဲ့ ငွေထုတ်လွှာ (Slip) ကို ဖြည့်ရတယ်။
  3. Dispatcher (Bank Teller): ဘဏ်ဝန်ထမ်းက စာရွက်ကို လက်ခံပြီး မှန်၊ မမှန် စစ်ဆေးတယ်။
  4. Store (Vault): ငွေတိုက်ထဲက ပိုက်ဆံ လျော့သွားတယ်။ (State Update ဖြစ်သွားတယ်)
  5. View (Balance Screen): လက်ကျန်ငွေ ပြောင်းသွားတာကို Customer က မြင်ရတယ်။

Customer အနေနဲ့ ငွေတိုက်ထဲကို ကိုယ်တိုင်ဝင်ပြီး ပိုက်ဆံ သွားယူပြေးလို့ လုံးဝ မရပါဘူး (Direct State Mutation လုပ်လို့ မရပါ)။ Slip သေချာဖြည့်ပြီး ဝန်ထမ်းကို ပေးမှသာ ရမှာပါ။ ဒါဟာ Flux ရဲ့ အနှစ်သာရပါပဲ။

Redux ဆိုတာက Flux ရဲ့ သဘောတရားကို ပိုကောင်းအောင်၊ ပိုရှင်းလင်းအောင် မွမ်းမံထားတာပါ။ အခုခေတ်မှာတော့ သုံးရ ပိုလွယ်တဲ့ Redux Toolkit (RTK) ကို အဓိက သုံးကြပါတယ်။

Redux Toolkit (RTK) နဲ့ ရေးပုံ

Section titled “Redux Toolkit (RTK) နဲ့ ရေးပုံ”

အရင်က Redux ရေးရတာ ဖိုင်တွေ အများကြီးနဲ့ ရှုပ်ထွေးပေမယ့်၊ အခု RTK မှာတော့ createSlice ကို သုံးလိုက်တာနဲ့ အရမ်းကို လွယ်ကူသွားပါပြီ။

productSlice.js
import { createSlice } from '@reduxjs/toolkit';
const productsSlice = createSlice({
name: 'products',
initialState: [],
reducers: {
addProduct: (state, action) => {
// Immer library ပါဝင်တဲ့အတွက် state ကို တိုက်ရိုက်ပြင်သလို ရေးလို့ရပါတယ်
state.push(action.payload);
},
removeProduct: (state, action) => {
return state.filter(product => product.id !== action.payload.id);
}
}
});
// Action creators တွေကို အလိုအလျောက် generate လုပ်ပေးပြီးသား ဖြစ်ပါတယ်
export const { addProduct, removeProduct } = productsSlice.actions;
// Reducer ကို store မှာ သုံးဖို့ export လုပ်ပေးပါ
export default productsSlice.reducer;

အဓိက ပါဝင်တဲ့ အရာများ

Section titled “အဓိက ပါဝင်တဲ့ အရာများ”
  1. Store: Application တစ်ခုလုံးရဲ့ Data တွေ အားလုံးကို သိမ်းဆည်းထားတဲ့ “ဗဟိုဘဏ်” ကြီးပါ။
  2. Slice: Feature တစ်ခုချင်းစီအတွက် သီးခြား ခွဲထုတ်ထားတဲ့ “ဌာနခွဲ” တွေပါ။ (ဥပမာ - Product Slice, User Slice)။
  3. Action: “ဘာအလုပ် လုပ်မယ်” ဆိုတာကို ညွှန်ကြားတဲ့ အမိန့်စာပါ။ (ဥပမာ - addProduct, removeProduct)။
  4. Reducer: အဲဒီ အမိန့်စာကို ဖတ်ပြီး Data ကို တကယ် ပြောင်းလဲပေးတဲ့ “မန်နေဂျာ” ပါ။

မှတ်ချက်: Redux Toolkit မှာ state.push လို့ တိုက်ရိုက် ရေးလို့ ရနေတာက၊ နောက်ကွယ်မှာ Immer ဆိုတဲ့ Library က အလိုအလျောက် ကူညီပေးနေလို့ပါ။ တကယ်တမ်း Redux ရဲ့ စည်းမျဉ်းအရတော့ State တွေဟာ Immutable (တိုက်ရိုက် ပြောင်းလဲခွင့် မရှိသော) အရာတွေ ဖြစ်ပါတယ်။

ဒီနည်းလမ်းကို သုံးခြင်းအားဖြင့် Action တွေနဲ့ Reducer တွေကို နေရာတစ်နေရာတည်းမှာ စုစည်းထားနိုင်တဲ့အတွက်၊ Code ပိုမို ရှင်းလင်းပြီး စီမံခန့်ခွဲရတာ အရမ်း လွယ်ကူသွားစေပါတယ်။

productsSlice.actions ဆိုတာ ဘာလဲ?

Section titled “productsSlice.actions ဆိုတာ ဘာလဲ?”

createSlice က reducers object ထဲမှာ ခင်ဗျား ရေးထားတဲ့ Method တစ်ခုချင်းစီအတွက် Action Creator Function လေးတွေကို အလိုအလျောက် Generate လုပ်ပေးပါတယ်။

ဥပမာ:

  • reducers ထဲမှာ addProduct(state, action) လို့ ရေးလိုက်တာနဲ့ ⇒ productsSlice.actions.addProduct ဆိုတဲ့ Function တစ်ခု အသင့် ရလာပါမယ်။
  • removeProduct လည်း အတူတူပါပဲ ⇒ productsSlice.actions.removeProduct ဆိုပြီး ရလာပါမယ်။

ဒီလို အလိုအလျောက် ထွက်လာတဲ့ Function တွေကို Destructure လုပ်ပြီး အပြင်ကို Export ထုတ်ချင်လို့ export const { addProduct, removeProduct } = productsSlice.actions; လို့ ရေးရတာပါ။

Action Creator က ဘာလုပ်ပေးတာလဲ?

Section titled “Action Creator က ဘာလုပ်ပေးတာလဲ?”

addProduct({ id: 1, name: 'Book' }) လို့ ခေါ်လိုက်တာနဲ့၊ Redux က အောက်ကလို Action Object တစ်ခုအနေနဲ့ အလိုအလျောက် ပြောင်းလဲပေးလိုက်ပါတယ်:

{ type: 'products/addProduct', payload: { id: 1, name: 'Book' } }

အဲဒီ type နာမည်ရှည်ကြီးကို ကိုယ်တိုင် လိုက်ရေးစရာ မလိုတော့တဲ့အတွက် စာလုံးပေါင်း မှားတဲ့ (Typo) ပြဿနာတွေ၊ Code ထပ်ခါထပ်ခါ ရေးရတဲ့ ပြဿနာတွေ အများကြီး လျော့ကျသွားပါတယ်။

ဘယ်နေရာမှာ သုံးလဲ?

Section titled “ဘယ်နေရာမှာ သုံးလဲ?”

UI Component တွေကနေ Data ပြောင်းချင်တဲ့အခါ (ဥပမာ Button နှိပ်တဲ့အခါ) dispatch လုပ်ဖို့ သုံးပါတယ်။

import { useDispatch } from 'react-redux';
import { addProduct } from './productSlice';
function AddButton() {
const dispatch = useDispatch();
return (
<button onClick={() => dispatch(addProduct({ id: Date.now(), name: 'Pen' }))}>
Add
</button>
);
}

productsSlice.reducer ကို ဘာကြောင့် Export Default လုပ်ရတာလဲ?

Section titled “productsSlice.reducer ကို ဘာကြောင့် Export Default လုပ်ရတာလဲ?”

Redux Store အကြီးကြီးကို တည်ဆောက်တဲ့အချိန်မှာ၊ Slice တစ်ခုချင်းစီမှာ ရှိတဲ့ Reducer တွေကို စုစည်းပြီး Store ထဲကို ထည့်ပေးရလို့ပါ။ ဥပမာ -

import { configureStore } from '@reduxjs/toolkit';
import productsReducer from './productSlice';
export const store = configureStore({
reducer: {
products: productsReducer
}
});

State (Data) ကို Component မှာ ဘယ်လို ဖတ်မလဲ?

Section titled “State (Data) ကို Component မှာ ဘယ်လို ဖတ်မလဲ?”
import { useSelector } from 'react-redux';
function ProductList() {
const products = useSelector(state => state.products); // Store ထဲက products တွေကို ယူမယ်
return (
<ul>
{products.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
);
}