01204223/react-flask
- หน้านี้เป็นส่วนหนึ่งของวิชา 01204223
เนื้อหา
เริ่มต้นและการติดตังซอฟต์แวร์ต่าง ๆ
node.js และ npm
เนื่องจาก react เป็น JavaScript framework เราจำเป็นต้องติดตั้งซอฟต์แวร์ที่เกี่ยวข้องเสียก่อน การใช้ JavaScript บนเครื่องเราเองนั้น เราต้องมีตัว runtime ที่ใช้ทำงานกับโปรแกรมภาษา JavaScript &nbps; ในทางฝั่ง server Node.js น่าจะเป็นระบบที่มีคนใช้มากที่สุด ที่มาพร้อมกับเครื่องมือประกอบต่าง ๆ มากมาย (มากมายจริง ๆ)
ในการจะใช้เครื่องมือบน node.js ได้นั้น เราจะต้องติดตั้งโปรแกรม npm (Node Package Manager) ด้วย ดังนั้น ในขั้นแรกเราจะติดตั้งทั้งสองอย่างไปด้วยกัน
การติดตั้งบน MacOS และ Ubuntu:
การติดตั้งบน Windows
เมื่อติดตั้งแล้ว ให้ลองเรียกทั้งสองคำสั่งด้านล่างใน terminal
node -v npm -v
ถ้ามีเลขเวอร์ชันขึ้นมาก็น่าจะเรียบร้อย
การสร้างโครง React project
ในการพัฒนาด้วย React เราจะเขียนโค้ดที่ไม่ได้ถูกนำไปรันบน browser โดยตรง เพราะว่าจะต้องมีการ preprocess อะไรก่อนมากมาย ซึ่งขั้นตอนเหล่านี้ถ้าเราต้อง setup เองทั้งหมดจะยุ่งยากมาก แต่เนื่องจาก environment ในการพัฒนาด้วย JavaScript นั้นมีเครื่องมือมากมาย เราจึงสามารถพึ่งพาระบบเหล่านั้นได้เลย
เราจะสร้างโครงโปรเจ็คด้วย vite โดยสั่ง (ให้เปิด terminal มาเรียกใช้งานเลย เพราะว่าจะมีคำสั่งที่ต้องเรียกค้างไว้ระหว่างพัฒนา)
npm create vite@latest first-react-app -- --template react
จะมีคำถามให้ตอบหลายคำถาม ถ้ามีการถามว่า
Install with npm and start now?
ให้เลือก No ไว้ก่อน เพราะว่าเราจะได้กดอะไรต่าง ๆ เอง เมื่อ npm ทำงานเสร็จ จะมีคำสั่งบอกให้เราเรียกเพื่อเริ่มติดตั้งไลบรารีและเริ่มเรียก dev server ดังด้านล่าง
cd first-react-app npm install npm run dev
ให้ทำตามรายการคำสั่งดังกล่าว
ึึึคำสั่ง npm install จะติดตั้งไลบรารีที่เกี่ยวข้องลงในไดเร็กทอรี node_modules (ซึ่งจะใหญ่ขึ้นเรื่อยๆ อาจจะทำดิสก์เต็มได้) เมื่อติดตั้งเสร็จจะมีข้อความประมาณนี้
added 156 packages, and audited 157 packages in 33s
ส่วนคำสั่ง
npm run dev
จะเป็นการเรียก development web server ให้ทำงาน ให้เรียกแล้วเปิด terminal ทิ้งไว้ เมื่อเรียกเสร็จโปรแกรมจะแสดง URL ให้เราเข้าดูหน้าเว็บ (น่าจะเป็น http://localhost:5173/ ) นอกจากนี้ ถ้าเราแก้ไขอะไรในโปรเจ็ค vite จะจัดการ build โค้ดทั้งหมดให้รวมทั้ง reload หน้าเว็บของเราใน browser ให้โดยอัตโนมัติ
ถ้าไม่มีข้อผิดพลาดอะไร ใน browser จะแสดงโลโก้ Vite และ React
- อ่านเพิ่มเติมเกี่ยวกับการทำงานของ vite
ทดลอง React เบื้องต้น
ก่อนที่เราจะทดลองพัฒนาแอพลิเคชัน เราจะศึกษาพื้นฐานการทำงานของ React ผ่านทางเว็บง่าย ๆ ก่อน ในไดเร็กทอรี first-react-app ที่เราสร้าง จะมีไฟล์
index.html
ซึ่งจะเป็นหน้าเว็บหลักของเรา ถ้ากดเขาไปดูจะพบหน้าเว็บที่เกือบ ๆ จะว่าง แต่มีส่วนโหลด /src/main.jsx อยู่
<!doctype html>
<html lang="en">
<!-- ## ละไว้บางส่วน ## -->
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
ส่วนที่เราจะเขียนโปรแกรมกันจริงๆ จะอยู่ในไดเร็กทอรี src อยู่ ในนั้นจะมีไฟล์เหล่านี้
- App.jsx // โค้ดของ component App (เราจะเขียนกันที่ไฟล์นี้ก่อน) - main.jsx // สร้าง component App และนำไปใส่ใน element id root - App.css // จัดการกับ style สำหรับ component App - index.css // style ของแอพโดยรวม
main.jsx
ให้ลองกดไปดูโค้ดใน main.jsx สักเล็กน้อย (เราจะไม่ได้แก้อะไร)
// ----- ไฟล์ main.jsx ------ (เพื่อกันความสับสนบางทีจะมีแจ้งชื่อไฟล์ไว้ด้านบน)
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
โค้ดดังกล่าวเป็นไฟล์ jsx ซึ่งเป็นไฟล์ที่มีการผสมกันระหว่าง JavaScript กับ template สังเกตว่าเราจะเขียน html tag ผสมกับโค้ดได้เลย ในส่วนนั้นจะมีการทำงานไม่ต่างกับ Jinja teamplate ที่เราเขียนใน Flask มาแล้ว
App.jsx
เราจะทำงานกับไฟล์นี้เป็นส่วนใหญ่ โค้ดปัจจุบันมีการทำงานหลายอย่างอยู่แล้ว แต่เราจะเริ่มทำใหม่กันตั้งแต่แรก
เราจะสร้าง component App ที่แทนแอพลิเคชันของเรา โดยในการเขียน เราจะประกาศเป็น function App ให้แก้ function ดังกล่าวในโค้ดให้เป็นดังด้านล่างก่อน
function App() {
let count = 5;
return (
<>
<button>-1</button>
{count}
<button>+1</button>
<br />
Bar: {count > 0 ? "*".repeat(count) : "(empty)"}
<br />
{count > 10 ? (
<>
high
<button>reset</button>
</>
) : (
<>low</>
)}
</>
)
}เมื่อ save แล้วจะเห็นผลลัพธ์เป็นดังนี้
ให้ลองแก้ค่าเริ่มต้นของ count เป็นค่าต่าง ๆ แล้วลองดูผลลัพธ์ เช่น เป็น 0, 10, 20 เป็นต้น ให้ลองเปลี่ยนค่าจนเห็นปุ่ม reset
ข้อสังเกตจากโค้ดด้านบน
- การใช้ <> </> (fragment) ในการประกาศส่วนที่เป็น html
- ในการเขียน tag br ถ้าเป็น html ธรรมดา เราสามารถเขียน <br> ได้เลย แต่ใน jsx เราต้องมีการเว้นช่องว่างและระบุ / เพื่อปิด tag ด้วย (ต้องเขียนเป็น <br />)
- การใช้ฟังก์ชัน
repeat - การใช้ conditional expression (เงื่อนไข ? ค่าเมื่อจริง : ค่าเมื่อเท็จ) ในการเขียน
เราสามารถใส่ JavaScript expression ได้โดยใส่ไว้ในเครื่องหมายปีกกา { } และในนั้นถ้าเราต้องการใส่ html เราต้องเปิดปิดด้วย <> </> ก่อน (สังเกตในส่วนเงื่อนไข low, high)
ถ้าสังเกต เราจะเห็นว่าใน ui ของเรามีปุ่ม -1 และ +1 อยู่ (รวมถึง reset) น่าจะเดาได้ว่าปุ่มทั้งสองจะทำอะไร แต่ตอนนี้กดไปก็ยังไม่มีอะไรเกิดขึ้น เพราะว่าเรายังไมไ่ด้เขียนโค้ดอะไรไปติดกับมัน
ทิศทางการ render และ state
ก่อนจะเขียน React ต่อไป ให้ลองคิดว่าถ้าเราต้องเขียนโปรแกรมเพื่อจัดการกับค่า count หลังการกดปุ่มทั้งสอง เราต้องทำอะไรบ้าง
เมื่อมีการกดปุ่ม เราน่าจะต้องดำเนินการดังนี้
- แก้ค่า count
- ปรับการแสดงผล count
- คำนวณสตริงแสดงดาวให้เป็นไปตาม count
- ตรวจสอบเงื่อนไขในการแสดงว่า high หรือ low พร้อมกับแสดงหรือซ่อนปุ่ม reset
ตัวอย่างโค้ดที่เราเขียนนี้ เป็นตัวอย่างของระบบ ui ที่มีความซับซ้อนไม่มากนัก แต่เราก็อาจจะพอนึกได้ว่า ถ้ามีการเปลี่ยนสถานะบางอย่าง จะส่งผลกระทบต่อหน้าจอหลายส่วน ซึ่งผลกระทบเหล่านี้ถ้าต้องจัดการหลาย ๆ สถานะพร้อมกันจะซับซ้อนมาก
แนวคิดหลักที่ทำให้ React นั้นเป็นที่นิยมคือการเปลี่ยนมุมมองการเขียนโค้ดจากการคิดว่าถ้ามีสถานะอะไรเปลี่ยน เราจะต้องปรับอะไรบ้าง และอะไรจะกระทบกันบ้างให้เป็น
- เราไม่ต้องสนใจว่าจะต้องแก้ไขอะไรบ้าง แต่ให้พิจารณาการ render หน้าจอใหม่ทั้งหมดเลย
แต่ถ้าทำตามวิธีดังกล่าวตรง ๆ หน้าเว็บเราคงจะกระพริบไปกระพริบมา ไม่ต่างจากการกด refresh ทุกครั้ง สิ่งที่ทำให้แนวคิดดังกล่าวนำมาใช้ในการพัฒนา ui ได้จริงคือการ render ลงไปที่ virtual DOM ก่อนที่จะปรับเปลี่ยนหน้าจอจริง ๆ เฉพาะในส่วนที่มีความแตกต่าง ทำให้การแก้ไขไม่ได้กระทบหน้าจอทั้งหมด
รูปด้านล่างเปรียบเทียบวิธีการจัดการกับ interaction สองแบบ
[รูป]
ด้านล่างแสดงตัวอย่างของการ update หน้าจอเป็นส่วนๆ
[รูป]
ไอเดียที่อยากทำ
เราอยากจะให้ปรับค่าตัวแปร count ถ้ามีการกดปุ่ม เราอาจจะแก้ส่วน button -1 โดยเพิ่มตัวจัดการ event onClick ลงไป ให้เป็นดังนี้
<button onClick={() => {count--;}}>-1</button>
หมายเหตุ: สังเกตการเขียน function ด้วย arrow
ให้ทดลองแก้แล้วทดลองดูผล
สังเกตว่าเมื่อกดปุ่ม เราก็ยังไม่เห็นอะไร
เป็นไปได้ว่าไม่มีการทำงาน หรือไม่มีการปรับค่า เราจะแก้โค้ดใหม่ ให้มีการ alert ค่า count มาดูด้วย ดังด้านล่าง
<button onClick={() => {count--; alert(count)}}>-1</button>
สังเกตว่าค่าตัวแปร count นั้นลงลงจริง แต่ไม่มีผลอะไรกับการแสดงบนหน้าจอเลย
