1. Home
  2. react-reducer-hook

React useReducer Hook အကြောင်း

article image

useReducer လို့ဆိုလိုက်တဲ့အချိန်မှာ Redux လားလို့ထင်ချင်ထင်မိပါလိမ့်မည်။ ဒါပေမဲ့ ဒီ post ကိုဖတ်ဖို့အတွက် Redux ကိုနားလည်စရာမလိုပါဘူး။ useReducer က React 16.8 မှာပါလာတဲ့ hook ဖြစ်ပါတယ်။
ဒီ post မှာ reducer ဆိုတဲ့အရာနှင့် useReducer ကို ရှုပ်ထွေးတဲ့ component state တွေမှာ ဘယ်လိုအသုံးပြုရမလဲဆိုတာ ရှင်းပြသွားချင်ပါတယ်။ useState ကိုအသုံးပြုပြီး ရှုပ်ထွေးတဲ့ state တွေကို ကိုယ်တိုင် manage လုပ်တာထက် useReducer ကို အသုံးပြုမယ်ဆိုရင် ပိုကောင်းပါတယ်။

Reducer ဆိုတာဘလဲ?
Reducer ဆိုတဲ့စကားလုံးက value နှစ်ခုကိုလက်ခံပြီး value တစ်ခုကို return ပြန်တဲ့ function ကိုခေါ်တဲ့ အခေါ်အဝေါ်တစ်ခုဖြစ်ပါတယ်။

Array တစ်ခုမှာရှိတဲ့ value တွေအားလုံးကို value တစ်ခုတည်းမှာ ပေါင်းစပ်ချင်တဲ့အခါ Array ရဲ့ function တစ်ခုဖြစ်တဲ့ reduce function ကိုသုံးလို့ရပါတယ်။ အောက်မှာဖော်ပြထားတဲ့အတိုင်း reducer function တစ်ခုရေးပြီး reduce ထဲမှာ pass လုပ်လို့ရပါတယ်။

let numbers = [1, 2, 3];
let sum = numbers.reduce((total, number) => {
    return total + number;
}, 0);;

ဘယ်လိုအလုပ်လုပ်သလဲဆိုတော့ array မှာရှိတဲ့ element တစ်ခုချင်းက ဒီ reducer function ကိုခေါ်ပြီးတော့ အရင် total နှင့် လက်ရှိ element ဖြစ်တဲ့ number ကို pass လုပ်ပါတယ်။ Return ပြန်တဲ့အချိန်တိုင်း total အသစ်ကို return ပြန်ပါတယ်။ Reduce ရဲ့ဒုတိယ argument မှာ pass တဲ့ 0 က total ရဲ့ မူလတန်ဖိုးဖြစ်ပါတယ်။ အပေါ်မှာပြထားတဲ့ နမူနာမှာ reduce ထဲမှာရှိတဲ့ function ကို ၃ခါ run ပါလိမ့်မည်။

  1. ပထမအကြိမ် (0,1) နဲ့ run ပြီးတော့ 1 return ပြန်
  2. ဒုတိယအကြိမ် (1,2) နဲ့ run ပြီးတော့ 3 return ပြန်
  3. တတိယအကြိမ် (3,3) နဲ့ run ပြီးတော့ 6 return ပြန်

reduce function က 6 return ပြန်ပြီးတော့ sum ထဲမှာ သိမ်းထားပါတယ်။

useReducer က ဘာအလုပ်လုပ်သလဲ?
အပေါ်က reduce function ရဲ့အလုပ်လုပ်ပုံနဲ့ အတူတူပါပဲ။ Reducer function တစ်ခုကို pass လုပ်ပြီးတော့ မူလတန်ဖိုးတစ်ခု သတ်မှတ်ပေးပါတယ်။ Reducer က လက်ရှိ state နဲ့ action တို့ကိုလက်ခံပြီးမှ state အသစ်တစ်ခု return ပြန်ပါလိမ့်မည်။

useReducer((state, action) => {
    return state + action;
}, 0);;

ဒါဆို ဒီ function ကို ဘယ်မှာသုံးမှာလဲ? action က ဘယ်ကပါလာတာလဲ? ကောင်းလိုက်တဲ့ မေးခွန်း။

useReducer က element နှစ်ခုပါတဲ့ array တစ်ခုကို return ပြန်ပါတယ်။ ပထမ element ကတော့ current state ဖြစ်ပြီးတော့ ဒုတိယ element ကတော့ dispatch function ဖြစ်ပါတယ်။

const [sum, dispatch] = useReducer((state, action)=>{
     return state+action;
 }, 0);;

ES6 ရဲ့ destructuring ကို အသုံပြုပြီးတော့ element နှစ်ခုကို ယူလိုက်တာဖြစ်ပါတယ်။

မှတ်ထားရမယ့်အရာက “state” ဆိုတဲ့နေရာမှာ value တစ်ခုခုထည့်လို့ရပါတယ်။ Object မက number တွေ၊ array တွေလည်း ထည့်လို့ရပါတယ်။

ဥပမာတစ်ခုလုပ်ကြည့်ရအောင်

import React, { useReducer } from ‘react’;
function Counter() {
 // First render will create the state, and it will
 // persist through future renders
 const [sum, dispatch] = useReducer((state, action) => {
 return state + action;
 }, 0);
return (
     <>
      {sum}
     <button onClick={() => dispatch(1)}>
        Add 1
     </button>
     </>
   );
};

Button နှိပ်လိုက်တဲ့အခါ dispatch function က action နေရမှာ 1 ဆိုတဲ့ value တစ်ခုကို ပေးပို့လိုက်ပါတယ်။ ပြီးနောက် current state မှာ အဲဒီ value ကို ပေါင်းထည့်လိုက်ပြီးတော့ component က state အသစ်တစ်ခုနဲ့အတူ render ပြန်လုပ်ပါတယ်။

ကျွန်တော်က “action” ကို {type: “INCREMENT_BY”, value: 1} ဒီလို ပုံစံနဲ့မလုပ်ဘဲနဲ့ ဥပမာပေးခဲ့ပါတယ်။ ဘာဖြစ်လို့လဲဆိုတော့ reducer ကိုသုံးတဲ့အခါ Redux ရဲ့ပုံစံအတိုင်း လိုက်လုပ်နေစရာမလိုလို့ပါပဲ။

ပိုမိုရှုပ်ထွေးတဲ့ ဥပမာတစ်ခု
Redux reducer နဲ့ဆင်တူတဲ့ ဥပမာတစ်ခုပြချင်ပါတယ်။ Shopping list ကို manage လုပ်တဲ့ component တစ်ခုတည်ဆောက်ချင်ပါတယ်။ ဒီနေရာမှာ useRef ကိုလည်း အသုံးပြုမှာဖြစ်ပါတယ်။

အရင်ဆုံး အသုံးပြုမယ့် hook နှစ်ခုကို import လုပ်ပါမယ်။

import React, {useReducer, useRef} from ‘react’;;

ပြီးတော့ ref နှင့် reducer ကို တည်‌ဆောက်တဲ့ component တစ်ခု တည်ဆောက်ပါမယ်။

function ShoppingList() {
   const inputRef = useRef();
   const [items, dispatch] = useReducer((state, action) => {
        switch (action.type) {
        // do something with the action
        }
    }, []);
   return (
      <>
        <form onSubmit={handleSubmit}>
          <input ref={inputRef} />
        </form>
        <ul>
          {items.map((item, index) => (
            <li key={item.id}>
              {item.name}
            </li>
           ))}
        </ul>
     </>
  );
};

ကျွန်တော်တို့ရဲ့ state မှာ empty array (useReducer ရဲ့ ဒုတိယ argument က state ရဲ့ initial value (မူလတန်ဖိုး) ဖြစ်တယ်) တစ်ခု initialize လုပ်ပါတယ်။ မကြာခင် reducer function ကိုဖြည့်စွပ်ပြီးတော့ array အသစ်တစ်ခု return ပြန်မှာဖြစ်ပါတယ်။

useRef Hook အ‌ကြောင်း ဒီနေရာမှာ ဖတ်ရှုနိုင်ပါတယ်။ React useReducer Hook

input element ကို form element ထဲမှာ ရေးထားပါတယ်။ ဘာဖြစ်လို့လဲဆိုတော့ submit button ကိုနှိပ်လိုက်တဲ့အချိန်မှာ submit function ကို trigger ဖြစ်စေဖို့ရန်အတွက်ပါ။ အခု list ထဲမှာ item တွေကိုထည့်ပေးမယ့် handleSubmit ဆိုတဲ့ function တစ်ခုတည်ဆောက်ပါမယ်။ ပြီးတော့ action ကို reducer ထဲမှာ handle လုပ်ပါမယ်။

function ShoppingList() {
  const inputRef = useRef();
  const [items, dispatch] = useReducer((state, action) => {
    switch (action.type) {
       case ‘add’:
          return [
             …state,
             {
               id: state.length,
               name: action.name
             }
          ];
       default:
          return state;
      }
 }, []);
function handleSubmit(e) {
     e.preventDefault();
     dispatch({
       type: ‘add’,
       name: inputRef.current.value
     });
     inputRef.current.value = ‘’;
 }
return (
 // … same …
 );
};

Reducer function က ‘add’ ဆိုတဲ့ action ကိုရရှိတဲ့အခါ array ထဲမှာပါပြီးသား item တွေနဲ့အတူ item အသစ်တစ်ခုပါဝင်တဲ့ array အသစ်တစ်ခု return ပြန်ပါမည်။

ဒီနေရာမှာ ကျွန်တော်တို့က item ရဲ့ id မှာ length ကိုသုံးထားပါတယ်။ တကယ့် app တွေရေးတဲ့အခါ ဒီလိုမျိုးမသုံးသင့်ပါဘူး။ Id တွေထပ်နေနိုင်ပြီး bug တွေလည်းဖြစ်စေနိုင်လို့ပါ။ (uuid https://www.npmjs.com/package/uuid, လို library မျိုးသုံးပေးသင့်ပါတယ်)။

Input box ထဲမှာ Enter နှိပ်လိုက်တဲ့အခါ handleSubmit ဆိုတဲ့ function ကို ခေါ်လိုက်ပါတယ်။ ဒီလို‌ခေါ်တဲ့အချိန်မှာ preventDefault ဆိုတဲ့ function ကို page reload မဖြစ်စေဖို့ရန်အတွက် ‌ခေါ်ထားဖို့လိုပါတယ်။ ပြီးတော့ dispatch function ကို action နဲ့အတူ ခေါ်လိုက်ပါတယ်။

ဒီ app မှာ ကျွန်တော်တို့ရဲ့ action က type ဆိုတဲ့ property နှင့်အတူ အခြားလိုအပ်တဲ့ data တွေပါဝင်တဲ့ object တစ်ခုဖြစ်ပါတယ်။<br>

Item ကို ဘယ်လို remove လုပ်မလဲ?
နောက်ထပ် delete ဆိုတဲ့ button တစ်ခုလုပ်ထည့်ပါမယ်။ အဲဒီ button ကို နှိပ်လိုက်တဲ့အချိန်မှာ dispatch function က type ရဲ့တန်ဖိုး ‘remove’ နှင့် ဖျက်ရမယ့် Item ရဲ့ index ရှိတဲ့ action ကို reducer function ဆီ ပေးပို့လိုက်ပါတယ်။

ပြီးတော့ reducer function မှာ ရောက်ရှိလာတဲ့ action ကို handle လုပ်ဖို့လိုပါတယ်။

function ShoppingList() {
   const inputRef = useRef();
   const [items, dispatch] = useReducer((state, action) => {
   switch (action.type) {
     case ‘add’:
     // … same as before …
     case ‘remove’:
     // keep every item except the one we want to remove
     return state.filter((_, index) => index != action.index);
     default:
       return state;
     }
   }, []);
function handleSubmit(e) { /*…*/ }
   return (
     <>
       <form onSubmit={handleSubmit}>
         <input ref={inputRef} />
       </form>
       <ul>
         {items.map((item, index) => (
            <li key={item.id}>
               {item.name}
               <button
                 onClick={() => dispatch({ type: ‘remove’, index })}
               >
               X
               </button>
             </li>
         ))}
       </ul>
     </>
    );
  };

ဒီ CodeSandbox မှာ run ကြည့်လို့ရပါတယ်။

ဒါဆိုရင် Redux မလိုတော့ဘူးလား?

useReducer ကိုမြင်လိုက်တာနဲ့ Redux မလိုတော့ဘူးလို့ အချို့ကထင်နေကြပါတယ်။ Redux က ပိုပြီးတော့ အသုံးနည်းတာပဲရှိတာပါ။ Context + useReducer ပေါင်းတာထက် Redux က ပိုပါတယ်။ Debugging လုပ်ဖို့အတွက် Redux DevTools ရှိတယ်။

စိတ်ကြိုက် ပြုပြင်ပြောင်းလဲနိုင်ဖို့ရန်အတွက် middleware တွေနဲ့ အခြား helper library ‌တွေလည်းအများကြီးရှိပါတယ်။ အဓိကကွာခြားချက်တစ်ခုကတော့ Redux မှာ app data တွေကို ဗဟိုပြုချုပ်ကိုင်ထားတဲ့ global store ရှိပြီး useReducer မှာတော့ component တစ်ခုချင်းစီအတွက် ရေးပေးရပါတယ်။

အဆုံးထိဖတ်ပေးတဲ့အတွက် ကျေးဇူးအများကြီးတင်ပါတယ်

😊😊😊


Comments

Let me know your opinion

Related Articles

Feedbacks