React มือใหม่ part 1: using TypeScript
เมื่อเพื่อนผมเขาอยากทำธุรกิจและผมอยากช่วยเหลือเขาเท่าที่ความสามารถพาไปได้ เราคุยกันว่าน่าจะใช้ React เป็นไลบรารีฝั่ง front end นี่จึงเป็นจุดเริ่มต้นของบทความอยากเล่าและอยากลอง React ด้วยการเริ่มต้นโค้ดจากศูนย์อีกครั้ง
เนื้อหาที่อยากเล่าใน part นี้ประกอบด้วย
- เตรียมความพร้อม เครื่องคอมฯและติดตั้งโปรแกรมที่จำเป็น
- สร้าง React ด้วย TypeScript โครงสร้างของโปรเจกต์
- Home Component ตัวอย่าง function component
- About Component ตัวอย่าง function component + array function
- Basic React Routing
- Lifecycle Methods
เตรียมความพร้อม
- เครื่อง MacOS ปี 2018
- MS VS Code ที่นี่ เป็น editor ช่วยเขียนโปรแกรม
- ดาวน์โหลด Node.js ที่นี่ แล้วติดตั้งให้เรียบร้อย
เมื่อเราติดตั้ง Node.js เราจะได้โปรแกรม NPM เป็นตัวจัดการ JavaScript packages ย่อมาจาก Node Package Manager
ติดตั้ง create-react-app
ที่ Terminal พิมพ์
npm install -g create-react-app
React ก็คือไลบรารี JavaScript ดังนั้นเราสามารถใช้ NPM ช่วยติดตั้งมันได้
มือใหม่อาจสงสัยว่าทำไมต้องพึ่งพา NPM? คำตอบที่เป็นหัวใจคือเราต้องการมันมาจัดการ JavaScript dependencies
คำว่า JavaScript dependencies นี้หมายถึง JavaScript package ที่มีมากกว่าหนึ่งและมันต้องทำงานร่วมกัน เวอร์ชันไหนเข้ากันได้ ปรับปรุงเวอร์ชัน เพิ่มและลบ package ต่างๆที่ต้องการ
npm install -g
จะบอกให้ติดตั้งโปรแกรมต่อไปนี้ในระดับ global สามารถเรียกใช้ได้ทุกที่ ส่วน create-react-app
คือชื่อโปรแกรมดังกล่าว
สร้าง React ด้วย TypeScript
จริงอยู่ React สามารถเขียนด้วย .js แต่เราจะเขียนมันด้วย TypeScript (.ts) แทน
มือใหม่อาจสงสัยว่าทำไมต้องพึ่งพา TypeScript? คำตอบที่เป็นหัวใจคือเราต้องการไทป์หรือชนิดข้อมูลเพื่อลดความผิดพลาดในขณะที่กำลังพัฒนาโปรแกรม
create-react-app try-react --template typescript
คำสั่งข้างต้นกล่าวว่าสั่งให้ใช้โปรแกรม create-react-app
สร้างโปรเจกต์ชื่อ try-react
โดยใช้ TypeScript
เข้าไปในโปรเจกต์แล้วพิมพ์
npm run build
คำสั่งนี้จะสร้าง folder ชื่อ build ภายในนั้นคือโปรเจกต์ของเราที่พร้อม deploy บน production server
ความแตกต่างระหว่าง production server กับ local server
local server นี้หมายถึงเครื่องคอมฯของเราเอง เมื่อติดตั้ง Node.js เราก็มี Node.js เป็นโปรแกรม web server คอยจัดการประดา requests ให้ ส่วน production server นั้นไม่ใช่คอมฯของเรา เราจะต้องติดตั้งหรือเลือกใช้บริการโปรแกรม web server ที่เข้าใจโปรเจกต์ของเราครับ
โปรเจกต์ที่ต้อง deploy บน production server (remote เพื่อ upload โปรเจกต์ไปวาง) ควรจะมีขนาดเล็กเพื่อให้ผู้ใช้งานโหลดได้ไวในขณะที่ใช้ความเร็วอินเตอร์เน็ตต่ำ คำสั่ง npm run build
จะทำหลายอย่างเพื่อให้โปรเจตก์เราพร้อมสำหรับเรื่องนี้ อ่านเพิ่มเติม ที่นี่
โครงสร้างโปรเจกต์
folder ชื่อ build ซึ่งเกิดจากคำสั่ง npm run build
สามารถลบและสั่งสร้างได้ตลอด โครงสร้างของโปรเจกต์เพิ่งสร้างขึ้นเป็นดังนี้
- node_modules ภายในคือ JavaScript dependencies สามารถลบและสั่งสร้างได้ตลอดด้วยคำสั่ง
npm install
- public ภายในคือ static assets หรือไฟล์ content ที่จำเป็นต่อ
npm run build
- src ย่อมาจาก source หรือไฟล์ตั้งต้นในการพัฒนาโปรเจกต์ ประกอบด้วยไฟล์
.tsx
คือ React component,.ts
คือ TypeScript,.css
คือ CSS และd.ts
คือ TypeScript ที่ TypeScript compiler ใช้เพื่อตรวจสอบไทป์ - .gitignore เป็นส่วนหนึ่งของการพัฒนาโปรเจกต์โดยมี Git เป็นผู้แล source code ใช้เพื่อละเว้น folder หรือกลุ่มไฟล์ที่เราไม่สนใจและไม่ต้องการ commit เข้า Git repository
- package.json (และ package-lock.json) ใช้กำหนด dependencies ทั้งหมดในโปรเจกต์ของเรา เป็นหัวใจของโปรเจตก์ที่สร้างจาก Node.js
- tsconfig.json ใช้ตั้งค่าเพื่อบอกกล่าวแก่ TypeScript compilter ให้ตรวจสอบไทป์ใน
.ts
การพัฒนา React ด้วย TypeScript จะอยู่ใน strict mode กล่าวคือจะเข้มงวดกับไทป์ หากเขียนผิดไวยากรณ์จะไม่ compile ให้ อ่านเพิ่มเติม ที่นี่
index.tsx
เปิดไฟล์ src/index.tsx
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
ไฟล์ใดก็ตามที่บรรจุ React component จะใช้สกุล .tsx ไฟล์ชื่อ index.tsx นี้คือจุดเริ่มต้นของเราและถูกเรียกว่า entry point
โปรดสังเกตว่า ReactDOM.render
ต้องการ 2 ค่า
- component ที่จะถูก render นั่นคือ
<App/>
ที่ถูกห่อหุ้มด้วยReact.StrictMode
- จุดที่จะ render ซึ่งก็คือ div element ในไฟล์ public/index.html ที่มี id ชื่อ root
App.tsx
<App/>
ถูกประกาศไว้ในไฟล์ src/app.tsx ฟังก์ชัน App
เมื่อเขียนเป็นแท็กเปิดและปิดจึงได้ว่า <App/>
function App() {
return (
<div className="App">
<header className="App-header">
...
</header>
</div>
);
}
เราเรียกการเขียนลักษณะนี้ว่า component
JSX
จากตัวอย่างโค้ดของ src/app.tsx หน้าตาของ component ใดๆจะถูก render หลังคำสั่ง return (...)
โดยไวยากรณ์ที่เขียนภายใน (...)
นี้เรียกว่า JSX ซึ่งไม่ใช่ HTML (JSX ย่อมาจาก JavaScript XML) หรือพูดง่ายๆคือ XML ที่ท้ายที่สุดจะถูกเปลี่ยนเป็น JavaScript/ECMAScript ปกติที่ browser เข้าใจ
เพราะความคุ้นเคยบ่อยครั้งที่ผมมักเขียน class แทนที่จะเขียน className เข้าไปในแท็ก มือใหม่พอจะทราบแล้วว่า class ใช้กับ HTML และแน่นอนว่า JSX ไม่รู้จักมัน
รันโปรเจกต์
พิมพ์คำสั่งต่อไปนี้เพื่อเริ่มทำงาน Node.js และดูผลลัพธ์ที่ได้
npm start
ที่ http://localhost:3000
การแก้ไขไฟล์ .tsx จะ re-render อัตโนมัติเราไม่ต้องไป stop แล้ว start server เอง (ดีใช่ไหมล้า~)
Home Component
เราจะสร้าง component แรกกัน ชื่อว่า Home
จาก src folder สร้างไฟล์ชื่อ Home.tsx
import React from 'react'function Home() {
return (
<div>Hello World! Home</div>
)
}export default Home
มือใหม่จะสังเกตว่าเครื่องหมาย ; ท้าย statement จะมีหรือไม่ก็ได้
About Component
เราจะสร้าง About component ที่เขียนต่างจาก Home component เล็กน้อย
สร้างไฟล์ src/About.tsx
import React, { FC } from 'react'const About: FC = () => {
return <div>I am About.</div>
}export default About
FC คือ function component เขียนด้วย arrow function
ทั้ง Home component และ About component ต่างกันแค่วิธีเขียนฟังก์ชันแค่นั้น มือใหม่ก็เลือกเอาตามใจชอบ
Basic React routing
คงดีไม่น้อยถ้าเราได้เพิ่ม Home และ About ไว้กับ routing เพื่อสลับการ render
เปิดไฟล์ src/index.tsx เพิ่ม BrowserRouter
import { BrowserRouter } from 'react-router-dom'
แต่ VS Code ไม่รู้จัก นั่นแสดงว่าเราต้องบอก npm ให้ช่วยติดตั้ง react-router-dom ก่อน
npm i react-router-dom
คำสั่ง install
สามารถเขียนย่อได้ด้วย i
เนื่องจากโปรเจกต์ใช้ TypeScript ดังนั้นเพิ่ม @Types ของ react-router-dom ด้วย
npm i --save-dev @types/react-router-dom
ไฟล์ package.json จะมีส่วนที่เรียกว่า
dependencies
และdevDependencies
สองส่วนนี้ต่างกันที่ devDependencies ใช้ในช่วงพัฒนาโปรเจกต์เท่านั้น จะไม่ถูก bundle เข้ากับโค้ด production
คราวนี้แทรก BrowserRouter เข้าไป
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
เท่ากับว่า component ใดภายใต้ App component ได้สมบัติการ routing
เปิดไฟล์ src/App.tsx ปรับปรุง JSX
import React from 'react';
import './App.css';
import { Route, Switch } from 'react-router-dom';
import Home from './Home';function App() {
return (
<div className="App">
<header className="App-header">
<Switch>
<Route path='/' component={Home}></Route>
</Switch>
</header>
</div>
);
}export default App;
ผลลัพธ์
เพิ่ม About component เข้าไปที่ /about
import About from './About';
...
<Switch>
<Route path='/about' component={About}></Route>
<Route path='/' component={Home}></Route>
</Switch>
ที่ http://localhost:3000/about
Lifecycle Methods
มือใหม่คงทราบว่า React ใช้กลไกของ virtual DOM แทนที่จะ render HTML ลงบน DOM จริงๆ ความเร็วที่เกิดจาการใช้ memory ส่วนนี้แลกกับการ re-render เฉพาะส่วนใดส่วนหนึ่งของ component ที่เกิดการเปลี่ยนแปลงเท่านั้นมันแสนคุ้มค่า
การเปลี่ยนแปลง (changed) ดังกล่าวเกิดจากสิ่งที่ React เรียกว่า State
State ก็คือออบเจ็กต์ที่บรรจุสารพัด properties ไว้ภายใน เมื่อฟังก์ชัน setState
ถูกเรียกก็กระตุ้นให้เกิดการ re-render
จากรูปข้างต้นนี้แบ่งได้ 2 phases
- Render phase
- Commit phase
ทั้ง 2 phases ประกอบด้วย Mounting, Updating และ Unmounting
Mounting จะจองหน่วยความจำ (initialization) และเพิ่ม component ไปยัง virtual DOM
Updating เกิดขึ้นเพื่อ re-render ผลคือ UI เกิดการเปลี่ยนแปลง (รวมถึง data ที่แสดงบน UI เปลี่ยนแปลง)
Unmounting เมื่อใดก็ตามที่ component ไม่ถูกใช้งานมันจะถูกลบออกจาก DOM
Lifecycle Methods ถือเป็นหัวใจของ React เขียนได้ 2 รูปแบบ
- Class-style components (ดั่งเดิม)
- Functional components
ซึ่งจะขอกล่าวรายละเอียดใน part ถัดไปนะครับ