JavaScript Fundamentals တွေကိုလည်း သိပြီဆိုရင်တော့ ကျနော်တို့ React ကိုစပြီး လေ့လာလို့ရပါပြီ။ React ရဲ့ JSX ဘက်ကိုမလှည့်ခင်မှာ အရင်ဆုံးအနေနဲ့ ကျနော်တို့ Pure React ကိုပဲလေ့လာကြရအောင်။ ဘာလို့လဲဆိုတော့ ကျနော် React ကိုစလေ့လာတုန်းက JSX ကြီးကိုမြင်ရတာ တမျိုးကြီးဖြစ်နေခဲ့ပါတယ်။ ဘာလို့ HTML ကို JavaScript ထဲထည့်ရေးရမှာလဲ ၊ ဘာလို့ နောက်ထပ် Transpile လုပ်ပေးဖို့လိုတဲ့ extra language ကြီးလိုတာလဲပေါ့။ အမှန်တကယ်တော့ React App တစ်ခုဖြစ်ဖို့အတွက် JSX မလိုပါဘူး။ ဒါ့ကြောင့် ဒီတစ်ခေါက်ရဲ့ အဓိက point ကတော့ JSX ကဘာလို့ React ရဲ့ eco system အတွက် make sense ဖြစ်တာလဲ ၊ ပြီးတော့နောက်တစ်ခုက ဒီ JSX နဲ့ React က Magic တွေသုံးနေတာမဟုတ်ဘူး ၊ ပုံမှန် JavaScript ရဲ့ function call တဲ့ပုံစံတွေပဲဆိုတာကို အဓိကသိစေချင်တာဖြစ်ပါတယ်။
Prerequisites
ဒီမှာလိုအပ်တာတွေကတော့ ကြိုက်နှစ်သက်ရာ
- Text Editor တစ်ခု (VSCode, Sublime, etc.)
- Modern Web Browser တစ်ခု (Preferably, Chrome or FireFox)
1. Setup
တစ်ခုသိထားသင့်တာကတော့ Project Structure ချတဲ့နေရာမှာ ကိုယ်ကြိုက်သလို Setup လုပ်လို့ရတာဖြစ်ပါတယ်။ React က Project Structure ဘယ်လိုဖြစ်နေဖြစ်နေ သူ့အတွက်အရေးမကြီးပါဘူး။ အောက်မှာ ကျနော် Setup လုပ်သွားမယ့် Structure ကတော့ test app တစ်ခုအတွက် Simple အဖြစ်ဆုံး ဖြစ်အောင်လုပ်ထားတာပါ။
အရင်ဆုံးအနေနဲ့ မိမိကြိုက်တဲ့ workspace တစ်ခုမှာ Project Folder တစ်ခု create လုပ်ပါမယ်။
cd ~/Projects
mkdir pure-react && cd pure-react
ပြီးရင် src
ဆိုတဲ့ folder တစ်ခု create လုပ်ပြီးတော့ အဲဒီ့ folder ထဲမှာပဲ index.html
ဆိုတဲ့ html file တစ်ခု create လုပ်ပါမယ်။
mkdir src && cd src && touch index.html
ဆိုတော့ Directory Structure က ဒီလိုဖြစ်နေပါမယ်။
.
└── src
├── App.js
└── index.html
ပြီးရင်တော့ ဒီ index.html
file ကို Text Editor တစ်ခုခုနဲ့ ဖွင့်လိုက်ပါ။ (ကျနော်ကတော့ VSCode ကိုသုံးပါမယ်။)
code .
Emmet
ဆိုတဲ့ autocomplete လုပ်ပေးတဲ့ extension တစ်ခုကိုသုံးပြီးတော့ html boilerplate တစ်ခုဆောက်လိုက်ပါမယ်။ (VSCode မှာတော့ တစ်ခါတည်းပါပြီးသားပါ။)
html:5 လို့ရိုက်ပြီး Tab ခေါက်လိုက်ရုံပါပဲ။
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
ပြီးရင်တော့ body ထဲမှာ script tag နှစ်ခုထည့်ပါမယ်။ ဒီ script တွေကတော့ React နဲ့ React-Dom library နှစ်ခုရဲ့ CDN link တွေဖြစ်ပါတယ်။
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pure React</title>
</head>
<body>
<script src="<https://unpkg.com/react@16/umd/react.development.js>" crossorigin></script>
<script src="<https://unpkg.com/react-dom@16/umd/react-dom.development.js>" crossorigin></script>
<!-- our code will start here -->
</body>
</html>
အခုဆိုရင်တော့ ကျနော်တို့ React ကို load လုပ်ပြီးသွားပါပြီ။ ကျနော်တို့ရဲ့ code တွေကိုတော့ ရဲ့အပေါ်မှာ script tag တစ်ခုထည့်ပြီး ရေးသွားမှာပါ။
2. Getting Started with Pure React
ပထမဆုံးအနေနဲ့ ကျနော်တို့လုပ်မှာက React နဲ့ render လုပ်မလုပ်သိဖို့အတွက် div
element တစ်ခုထည့်ပါမယ်။ body tag အစ အောက် (သို့) ပထမ script tag ရဲ့အပေါ်နားမှာပါ။
<body>
<div id="root">React is not loaded yet</div>
...
အရင်ဆုံး ဒီ index.html
file ကိုဖွင့်ကြည့်ရအောင်။ လောလောဆယ်မှာမြင်ရမှာကတော့ React is not loaded yet ဆိုတဲ့ စာတစ်ကြောင်းပဲဖြစ်ပါတယ်။ ဒါပေမယ့် ကျနော်တို့ React ကို script tag နှစ်ခုနဲ့ load လုပ်ခဲ့ပြီးဖြစ်တဲ့အတွက် Browser ရဲ့ inspector ကိုဖွင့်ပြီး console မှာ React
လို့ရိုက်ကြည့်ရင်တော့ အောက်ကလိုမြင်ရမှာဖြစ်ပါတယ်။
React
{Children: {…}, Fragment: Symbol(react.fragment), Profiler: Symbol(react.profiler), Component: ƒ, PureComponent: ƒ, …}
Children: {map: ƒ, forEach: ƒ, count: ƒ, toArray: ƒ, only: ƒ}
Component: ƒ Component(props, context, updater)
Fragment: Symbol(react.fragment)
Profiler: Symbol(react.profiler)
PureComponent: ƒ PureComponent(props, context, updater)
StrictMode: Symbol(react.strict_mode)
Suspense: Symbol(react.suspense)
cloneElement: ƒ cloneElementWithValidation(element, props, children)
createContext: ƒ createContext(defaultValue, calculateChangedBits)
createElement: ƒ createElementWithValidation(type, props, children)
createFactory: ƒ createFactoryWithValidation(type)
createRef: ƒ createRef()
forwardRef: ƒ forwardRef(render)
isValidElement: ƒ isValidElement(object)
lazy: ƒ lazy(ctor)
memo: ƒ memo(type, compare)
useCallback: ƒ useCallback(callback, deps)
useContext: ƒ useContext(Context, unstable_observedBits)
useDebugValue: ƒ useDebugValue(value, formatterFn)
useEffect: ƒ useEffect(create, deps)
useImperativeHandle: ƒ useImperativeHandle(ref, create, deps)
useLayoutEffect: ƒ useLayoutEffect(create, deps)
useMemo: ƒ useMemo(create, deps)
useReducer: ƒ useReducer(reducer, initialArg, init)
useRef: ƒ useRef(initialValue)
useState: ƒ useState(initialState)
version: "16.13.1"
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {ReactCurrentDispatcher: {…}, ReactCurrentOwner: {…}, IsSomeRendererActing: {…}, ReactDebugCurrentFrame: {…}, assign: ƒ, …}
__proto__: Object
ဒီမှာမြင်ရတာတွေကတော့ React ရဲ့ core api တွေပဲဖြစ်ပါတယ်။ ဒါဆိုရင်ကျနော်တို့ React ကိုလည်း load လုပ်ထားတာတွေ့ရပြီဆိုရင်တော့ အရိုးရှင်းဆုံး Component လေးတစ်ခုကို တကယ်ဆောက်ပြီးတော့ render လုပ်ကြည့်ကြပါမယ်။
Creating a React Component
...
<!-- our code will start here -->
<script>
const App = () => React.createElement(
'div',
{},
React.createElement('h1', {}, 'Hello, My Dogs'),
)
</script>
</body>
</html>
ဒီ code ကို walkthrough လုပ်ရမယ်ဆိုရင်တော့ အရင်ဆုံးအနေနဲ့ *
- App* ဆိုတဲ့ const တစ်ခုကိုတွေ့ရမှာဖြစ်ပြီး သူ့ကို assign လုပ်ထားတာကတော့ Arrow Function တစ်ခုဖြစ်ပါတယ်။
- ဒီ Arrow Function ဟာ ရှေ့က article မှာပြောခဲ့တဲ့ implicit return ကိုသုံးပြီး return ပြန်ထားတာတွေ့ရမှာဖြစ်ပါတယ်။
- return ပြန်ထားတာကတော့ React ရဲ့ createElement ဆိုတဲ့ method ရဲ့ result ဖြစ်ပါတယ်။ ဆိုတော့ App ရဲ့ return ပြန်တာက createElement ရဲ့ return ပါပဲ။
- React.createElement မှာ argument သုံးခုရှိတာကိုတွေ့ရမှာပါ။
- ပထမတစ်ခုမှာ div ဆိုပြီးသတ်မှတ်ထားတာဆိုတော့ ကျနော်တို့ div element တစ်ခု create လုပ်မယ်လို့ပြောတာပါပဲ။
- နောက်တစ်ခုမှာ လောလောဆယ်တော့ Empty Object တစ်ခုပဲ သတ်မှတ်ထားပါတယ်။ ဒီ second argument က ဘာကိုလက်ခံတာလဲဆိုတာကို နောက်မှာဆက်ကြည့်ပါမယ်။
- နောက်ဆုံးမှာလည်း *React.createElement ဆိုတဲ့ function ကို ခေါ်ထားတာဖြစ်တဲ့အတွက် နောက်ထပ် element တစ်ခု create လုပ်နေတာပဲဖြစ်ပါတယ်။ ဒီတစ်ခေါက်ကတော့ h1 element တစ်ခုဖြစ်ပြီးတော့ သူ့မှာ “Hello, My Dogs” ဆိုတဲ့ စာသားတစ်ခုရှိနေမှာဖြစ်ပါတယ်။ အခု App ဆိုတဲ့ React Component တစ်ခုကျနော်တို့ တည်ဆောက်လိုက်တာဖြစ်ပါတယ်။ အခုနေကျနော်တို့ရဲ့ index.html ကိုပြန်ဖွင့်ကြည့်ရင် “React is not loaded yet” ဆိုတာပဲမြင်နေရဦးမှာဖြစ်ပါတယ်။ ကျနော်တို့ ဒီ App Component ကို render မှမလုပ်ရသေးတာကိုး။
React Component တွေကဘာနဲ့တူလဲဆိုတော့ စတစ်ကာ တွေလိုပါပဲ။ ဥပမာ - စာအုပ်အဖုံးကို DOM လို့မြင်ကြည့်ရအောင်။ စတစ်ကာ တွေက အကာခွာပြီးမကပ်မချင်း ဒီအတိုင်းသူ့ဟာနဲ့သူရှိနေမှာဖြစ်ပါတယ်။ ဘယ်နေရာကပ်ကပ် ကပ်လို့ရတာပေါ့။ Component တစ်ခုကို Render လုပ်တယ်ဆိုတာက အကြမ်းအားဖြင့်ပြောရမယ်ဆိုရင် စတစ်ကာ တစ်ခုကို အဖုံးပေါ်မှာကပ်လိုက်သလိုပါပဲ။
Rendering a React Component
...
<!-- our code will start here -->
<script>
...
// Render
ReactDOM.render(
React.createElement(App),
document.getElementById('root'),
)
</script>
</body>
</html>
ဒီမှာဆိုရင်တော့ ReactDOM library ရဲ့** render** ဆိုတဲ့ method ကိုသုံးပြီးတော့ render လုပ်တာကိုတွေ့ရမှာပါ။
- ပထမ argument က render လုပ်ချင်တဲ့ component ဖြစ်ပြီးတော့
- ဒုတိယ argument ကတော့ ဘယ်မှာ render လုပ်မလဲကို target သတ်မှတ်တာဖြစ်ပါတယ်။ ဒီမှာတော့ ကျနော်တို့ “root” ဆိုတဲ့ id ရှိတဲ့ element ကိုသတ်မှတ်ထားပါတယ်။ ဒါကိုကျနော်တို့အစောတုန်းကတည်းက ရေးထားခဲ့ပါတယ်။
အခု index.html ကိုဖွင့်ကြည့်ရင်တော့ “Hello, My Dogs” ကိုတွေ့ရမှာဖြစ်ပြီးတော့ သူ့ကိုတစ်ချက် inspect လုပ်ကြည့်ရင် React က ဘယ်လို render လုပ်သွားလဲဆိုတာကိုတွေ့နိုင်ပါတယ်။
ဒီနေရာမှာ သတိထားသင့်တာကတော့ render လုပ်ဖို့အတွက် target လုပ်ခံရတဲ့ element ရဲ့ content တွေက ပျက်သွားတာပဲဖြစ်ပါတယ်။ အဲဒီ့အစား ကျနော်တို့ရဲ့ component က content တွေဝင်သွားမှာဖြစ်ပါတယ်။
Cleanup
Component တွေရဲ့ အဓိကအားသာချက်ကတော့ ပြန်သုံးလို့ရတာပဲဖြစ်ပါတယ်။ ပုံစံအတူတူပဲဖြစ်ပြီးတော့ အထဲက content ပဲကွာမယ့်အရာတွေကို Component တစ်ခုအနေနဲ့ပဲထားလိုက်လို့ရပါတယ်။ ဒါဆိုဒီလို Component တစ်ခုဆောက်ကြည့်ရအောင်။
အရင်ဆုံးအနေနဲ့ အဲဒါမလုပ်ခင်မှာ ကျနော်နဲ့အတူ လိုက်ရေးနေတာဆိုရင် index.html file ကိုကြည့်ပြီးဘယ်လိုခံစားရလဲမသိဘူး။ ကျနော်ကတော့ ဒါကြီးကြည့်ရတာ ရွံလာပြီ 😂။ ဒါကြောင့်အရင်ဆုံး ခွဲထုတ်ရအောင်။ ခုနကပြောခဲ့သလိုပဲ React ဟာ ကျနော်တို့ဘယ်လို structure ချချ doesn’t care ပါ။ src folder ထဲမှာပဲ App.js ဆိုတဲ့ file တစ်ခုဆောက်ပြီးတော့ ခုနက script tag ထဲက ကျနော်တို့ရဲ့ code တွေအကုန်လုံးကို cut ပြီး App.js ထဲမှာ paste လုပ်ပါမယ်။ ပြီးရင်တော့ ခုနက script tag ကို App.js ကို load လုပ်ဖို့ပြောင်းပါမယ်။ ဆိုတော့ index.html နဲ့ App.js ဟာ ဒီလိုဖြစ်သွားပါမယ်။
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pure React</title>
</head>
<body>
<div id="root">React is not loaded yet</div>
<script src="<https://unpkg.com/react@16/umd/react.development.js>" crossorigin></script>
<script src="<https://unpkg.com/react-dom@16/umd/react-dom.development.js>" crossorigin></script>
<script src="./App.js"></script>
</body>
</html>
App.js
// App Component
const App = () => React.createElement(
'div',
{},
React.createElement('h1', {}, 'Hello, My Dogs'),
)
// Render
ReactDOM.render(
React.createElement(App),
document.getElementById('root'),
)
နောက် code တွေကို ဒီ App.js ထဲမှာပဲရေးမှာဖြစ်ပါတယ်။
Reusable Components
ကျနော်တို့မှာ ခွေးလေးတွေရဲ့ data ပါတဲ့ Array တစ်ခုရှိမယ်ဆိုကြပါတော့။ ဒီ Data မှာပါတဲ့အတိုင်း ကျနော်တို့ ပြဖို့အတွက်ကို ကျနော်တို့ပြင်ကြရအောင်။ အရင်ဆုံး Dog Component တစ်ခု ဆောက်ပါမယ်။ ဒီ component ဟာ reusable ဖြစ်ရမှာပါ။ လောလောဆယ်တော့ div တစ်ခုထဲမှာ h3 element တစ်ပဲရှိနေပါမယ်။
const Dog = () => React.createElement(
'div',
{},
React.createElement('h3'),
)
App Component မှာ အရင်ဆုံး implicit return မလုပ်တော့ပဲ myDogs ဆိုတဲ့ array တစ်ခုရှိပါမယ်။ ပြီးမှ သပ်သပ် return keyword နဲ့ return ပြန်ပါမယ်။
const App = () => {
const myDogs = [
{ name: 'ဘလက်ကီ', breed: 'mixed', color: 'အနက်' },
{ name: 'ဟန်နီ', breed: 'mixed', color: 'အညိုဖြော့' },
{ name: 'ဘော်ဘီ', breed: 'pomeranian', color: 'အဖြူ' },
]
return React.createElement(
'div',
{},
React.createElement('h1', {}, 'Hello, My Dogs'),
)
}
myDogs ဆိုတဲ့ array ရဲ့ object တစ်ခုချင်းမှာ name ၊ breed ၊ color ဆိုတဲ့ property သုံးခုပါပါတယ်။ ဒါဟာ Dog component ကို pass ပေးရမယ့် data ပဲဖြစ်ပါတယ်။ React မှာတော့ ဒီလို Parent Component က Child Component ကို data pass ပေးတာကို props pass တယ်လို့ခေါ်ပါတယ်။ ဒါဆိုအရင်ဆုံး Dog Component ဘက်မှာ ဒီ props တွေကိုပြဖို့အရင်ပြင်ပါမယ်။
const Dog = (props) => React.createElement(
'div',
{},
React.createElement('h3', {}, props.name),
React.createElement('h3', {}, props.breed),
React.createElement('h3', {}, props.color),
)
ပြီးရင်တော့ App Component မှာ Dog Component ကို props pass ပေးတာလုပ်ရပါမယ်။
// App Component
const App = () => {
const myDogs = [
{ name: 'ဘလက်ကီ', breed: 'mixed', color: 'အနက်' },
{ name: 'ဟန်နီ', breed: 'mixed', color: 'အညိုဖြော့' },
{ name: 'ဘော်ဘီ', breed: 'pomeranian', color: 'အဖြူ' },
]
return React.createElement(
'div',
{},
[
React.createElement('h1', {}, 'Hello, My Dogs'),
React.createElement(Dog, myDogs[0]),
React.createElement(Dog, myDogs[1]),
React.createElement(Dog, myDogs[2]),
],
)
}
အခု ပြန် run ကြည့်ရင်တော့ ဒီလိုမြင်ရမှာပါ။
ဒီမှာ သတိထားမိရင်တော့ App Component ထဲမှာကျတော့ နောက်ဆုံး argument ကို Array အနေနဲ့တွေ့ရမှာဖြစ်သလို Dog Component ထဲမှာကျတော့ ဒီအတိုင်း createElement ၃ခါ arugment ပေးထားတာတွေ့ရမှာပါ။ ကျနော်တမင်ဘာလို့ဒီလိုလုပ်ထားလဲဆိုရင် ဒီဟာက Array ပဲဖြစ်ဖြစ် အခါခါပဲ argument အနေနဲ့ pass pass မကွာဘူးဆိုတာကိုပြချင်လို့ဖြစ်ပါတယ်။ ဒီ property ကိုတော့ Variable Arity လို့ခေါ်ပါတယ်။
ဒီမှာ Array ကို သုံးခါရေးနေရတာအဆင်မပြေဘူး ၊ ဒါ့ကြောင့် refactor လုပ်ရအောင်။
// App Component
const App = () => {
const myDogs = [
{ name: 'ဘလက်ကီ', breed: 'mixed', color: 'အနက်' },
{ name: 'ဟန်နီ', breed: 'mixed', color: 'အညိုဖြော့' },
{ name: 'ဘော်ဘီ', breed: 'pomeranian', color: 'အဖြူ' },
]
return React.createElement(
'div',
{},
React.createElement('h1', {}, 'Hello, My Dogs'),
myDogs.map((dog) => React.createElement(Dog, { ...dog }))
)
}
Dog Component ကိုလည်းဒီလိုပြင်လို့ရပါတယ်။
const Dog = (props) => React.createElement(
'div',
{},
Object.values(props).map((val) => React.createElement('h3', {}, val)),
)
ဒီလို Refactor လုပ်လိုက်တာကိုကြည့်ခြင်းအားဖြင့် ဘာ့ကြောင့် JavaScript fundamental တွေလိုအပ်လဲဆိုတာ မြင်လာမယ်ထင်ပါတယ်။
3. Conclusion
ကျနော်တို့ အခုလေ့လာခဲ့တာကတော့ React ကို Bundling, JSX ဘာမှမသုံးပဲ Pure app တစ်ခုဆောက်ခဲ့တာပဲဖြစ်ပါတယ်။ ဒီ article ရဲ့ အဓိက take away ကတော့ ဒီလို ဘာ tooling မှမသုံးပဲ React app ရေးလို့ရတဲ့အကြောင်းနဲ့ နောက် article တွေမှာတွေ့ရမယ့် JSX ဆိုတာက ဘာလို့ make sense ဖြစ်တာလဲဆိုတာကို ပေါ်လွင်ဖို့အတွက်ဖြစ်ပါတယ်။