[Workshop] ทำแอพคำนวณ BMI ด้วย React.js
![[Workshop] ทำแอพคำนวณ BMI ด้วย React.js](/_vercel/image?url=%2Fimages%2F2023%2F05%2Fbmi-calculator-1.png&w=828&q=80)
สวัสดีครับ Workshop นี้เป็นหนึ่งใน Workshop ในคอร์สเรียน สอนเขียนเว็บด้วย React.js นะครับ ตัวแอพนี้จะเป็น BMI Calculator หรือโปรแกรมคำนวณค่าดัชนีมวลกายนั่นเอง หลังจากที่เราเรียนคอร์ส Intro to React ตอนที่ 1 ไปแล้ว ก็นำเอาสิ่งที่เรียน มาลองประยุกต์ทำแอพแบบง่ายๆ กันดูครับ
สอนเขียนเว็บด้วย React + TypeScript ปี 2023 (Intro to React) ตอนที่ 1สวัสดีครับ คอร์สนี้เป็นคอร์สเรียน React + TypeScript ที่ผมลองทำขึ้นมา เป้าหมายคือ เป็นเนื้อหาเบื้องต้น พื้นฐานสำหรับคนที่ไม่มีพื้นฐาน React + TypeScript มาก่อนเลย ให้สามารถทำเว็บไซต์ และ Deploy เว็บของเราได้ เนื้อหา ประมาณ 2-3 ชั่วโมง (แบบ Video)
Video Tutorial
Overview
ตัวแอพ ไม่มีอะไรมากครับ เป็นเว็บหน้าเดียว เพื่อคำนวณค่า BMI จากที่ผู้ใช้ทำการใส่ลงไป และแสดงค่า รวมถึงอธิบายผลลัพธ์ออกมาได้ สิ่งที่จะได้จาก Workshop นี้ คือ
- สร้างโปรเจ็ค React ด้วย Vite + TypeScript
- การใช้งาน state
useState()
- การใช้ Component การส่ง Props
- การ handle
onChange
ค่าจาก input - ตัวอย่างการใช้ ref
useRef
(จะมีสอนในตอนที่ 2 เรื่องของ Form ครับ)
Step 1 - เริ่มต้นสร้างโปรเจ็ค
เราจะสร้างโปรเจ็ค ด้วย Vite นะครับ ด้วยคำสั่งนี้
npm create vite@latest bmi-calculator -- --template react-ts
จากนั้น เปิดโปรเจ็คและทำการติดตั้ง dependencies
cd bmi-calculatornpm install
# start dev servernpm run dev
Step 2 - สร้าง State และ Markup
สร้าง state เพื่อเก็บ weight height และ bmi
const [weight, setWeight] = useState(0)const [height, setHeight] = useState(0)const [bmi, setBmi] = useState(0)
ค่า state พวกนี้ จะถุกอัพเดท ก็ต่อเมื่อ input มีการเปลี่ยนแปลงค่า ซึ่ง เราสามารถใช้ event onChange
ได้ เวลาที่ input onChange เราก็จะไปเรียก function handleOnChange
จากนั้น ใน function นั้นก็ทำการเช็คว่า change จาก input name อะไร ก็ทำการ set state นั้นๆ
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target
if (name === 'weight') { setWeight(Number(value)) } else if (name === 'height') { setHeight(Number(value)) }}
return ( <label htmlFor="weight">น้ำหนัก (kg)</label> <input type="number" name="weight" onChange={handleOnChange} />
<label htmlFor="height">ส่วนสูง (cm)</label> <input type="number" name="height" onChange={handleOnChange} />)
Step 3 - การคำนวณ BMI
เราจะใช้สูตรคือ น้ำหนัก / (ส่วนสูง ยกกำลังสอง) ก็ได้เป็นแบบนี้
const calculateBmi = () => { // const bmi = weight / ((height / 100) \* (height / 100))
const bmi = weight / (height / 100) ** 2 setBmi(bmi)}
ไฟล์ App.tsx
หลังจาก มี markup และ handle onChange และ calculate ก็จะได้เป็นแบบนี้
import { useState } from 'react'
import './App.css'
function App() { const [weight, setWeight] = useState(0) const [height, setHeight] = useState(0) const [bmi, setBmi] = useState(0)
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target
if (name === 'weight') { setWeight(Number(value)) } else if (name === 'height') { setHeight(Number(value)) } }
const calculateBmi = () => { // const bmi = weight / ((height / 100) * (height / 100))
const bmi = weight / (height / 100) ** 2 setBmi(bmi) }
return ( <div className="bmi-app"> <h1 className="title">BMI Calculator</h1> <p className="subtitle">โปรแกรมคำนวณค่าดัชนีมวลกาย - BMI</p>
<label htmlFor="weight">น้ำหนัก (kg)</label> <input type="number" name="weight" onChange={handleOnChange} />
<label htmlFor="height">ส่วนสูง (cm)</label> <input type="number" name="height" onChange={handleOnChange} />
<button type="button" onClick={calculateBmi}> คำนวณ </button>
<hr /> </div> )}
export default App
ใน Video ผมลืมพูดไปเรื่องของ event ในฟังค์ชั่น handleOnChange()
เนื่องจากเจอ auto suggest จาก Copilot เลยลืม
ตัว event ปกติ เราจะใช้เป็น type React.ChangeEvent
และใส่ HTMLInputElement
เป็น generic ให้รู้ว่า change event ของ html input นั่นเอง
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target
if (name === 'weight') { setWeight(Number(value)) } else if (name === 'height') { setHeight(Number(value)) }}
Step 4 - แสดงผลลัพธ์ BMI
ส่วนนี้คือเอาค่า BMI มาแสดงผลลัพธ์ว่าเราผอม อ้วน หรืออยู่ในเกณฑ์ โดยสูตรเราสามารถไปหาดูได้ครับ ว่าเค้าใช้ค่าไหน แต่ในตัวอย่าง ผมให้ Github Copilot มัน auto ให้ ก็เลยได้เป็นแบบนี้
const checkBmiResult = () => { if (bmi === 0) return '-' if (bmi < 18.5) return 'อยู่ในเกณฑ์น้ำหนักน้อย / ผอม' if (bmi < 25) return 'อยู่ในเกณฑ์ปกติ (สุขภาพดี)' if (bmi < 30) return 'อยู่ในเกณฑ์ท้วม / โรคอ้วนระดับ 1' if (bmi < 35) return 'อยู่ในเกณฑ์อ้วน / โรคอ้วนระดับ 2' if (bmi >= 35) return 'อยู่ในเกณฑ์อ้วนมาก / โรคอ้วนระดับ 3'}
กำหนดสีให้มัน เพื่อเอาไว้แสดง result แต่ละสี ให้ดูสวยงาม
const getResultClass = () => { if (bmi < 18.5) return 'gray' if (bmi < 22.9) return 'green' if (bmi < 24.9) return 'yellow' return 'red'}
ส่วน Result BMI
<div className="result"> <p>ค่า BMI คือ: {bmi}</p> <p>ผลลัพธ์</p> <p className={getResultClass()}>{checkBmiResult()}</p></div>
Step 5 - สร้าง Component สำหรับ BMI Result
เราสร้าง Component สำหรับ BMI Result แยกไปอีก component เพื่อให้แยกการทำงานอย่างชัดเจน ตอนนี้ไฟล์ components/BmiResult.tsx
จะเป็นแบบนี้
interface Props { bmi: number}
const BmiResult = ({ bmi }: Props) => { const checkBmiResult = () => { if (bmi === 0) return '-' if (bmi < 18.5) return 'อยู่ในเกณฑ์น้ำหนักน้อย / ผอม' if (bmi < 25) return 'อยู่ในเกณฑ์ปกติ (สุขภาพดี)' if (bmi < 30) return 'อยู่ในเกณฑ์ท้วม / โรคอ้วนระดับ 1' if (bmi < 35) return 'อยู่ในเกณฑ์อ้วน / โรคอ้วนระดับ 2' if (bmi >= 35) return 'อยู่ในเกณฑ์อ้วนมาก / โรคอ้วนระดับ 3' }
const getResultClass = () => { if (bmi < 18.5) return 'gray' if (bmi < 22.9) return 'green' if (bmi < 24.9) return 'yellow' return 'red' }
return ( <div className="result"> <p>ค่า BMI คือ: {bmi}</p> <p>ผลลัพธ์</p> <p className={getResultClass()}>{checkBmiResult()}</p> </div> )}
export default BmiResult
และไฟล์ App.tsx
ก็ import BmiResult
มาใช้ ผลลัพธ์ก็ได้แบบนี้
import { useState } from 'react'import BmiResult from './components/BmiResult'
import './App.css'
function App() { const [weight, setWeight] = useState(0) const [height, setHeight] = useState(0) const [bmi, setBmi] = useState(0)
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target
if (name === 'weight') { setWeight(Number(value)) } else if (name === 'height') { setHeight(Number(value)) } }
const calculateBmi = () => { // const bmi = weight / ((height / 100) * (height / 100))
const bmi = weight / (height / 100) ** 2 setBmi(bmi) }
return ( <div className="bmi-app"> <h1 className="title">BMI Calculator</h1> <p className="subtitle">โปรแกรมคำนวณค่าดัชนีมวลกาย - BMI</p>
<label htmlFor="weight">น้ำหนัก (kg)</label> <input type="number" name="weight" onChange={handleOnChange} />
<label htmlFor="height">ส่วนสูง (cm)</label> <input type="number" name="height" onChange={handleOnChange} />
<button type="button" onClick={calculateBmi}> คำนวณ </button>
<hr />
<BmiResult bmi={bmi} /> </div> )}
export default App
ปรับแต่ง CSS เล็กๆน้อยๆ เมื่อเราลองดูหน้าเว็บ เว็บเราจะมีหน้าตาสวยงาม แบบนี้
อ่อ ใน Video ผมยกตัวอย่าง useRef ที่ยังไม่ได้สอนไว้คร่าวๆ เดี๋ยวจะอธิบายเพิ่มเติมในเรื่อง Form นะครับ แต่สำหรับใครอยากใช้ ref ก็ทำได้ครับ แบบนี้
import { useRef, useState } from 'react'
import './App.css'
function App() { const [bmi, setBmi] = useState(0)
const heightRef = useRef < HTMLInputElement > null const weightRef = useRef < HTMLInputElement > null
const calculateBmi = () => { const weight = weightRef.current?.value || 0 const height = heightRef.current?.value || 0
const bmi = Number(weight) / (Number(height) / 100) ** 2 setBmi(bmi) }
const checkBmiResult = () => { return <span>TODO</span> }
return ( <> <h1>BMI Calculator</h1> <p>โปรแกรมคำนวณค่าดัชนีมวลกาย - BMI</p>
<label htmlFor="weight">น้ำหนัก (kg)</label> <input type="number" name="weight" ref={weightRef} />
<label htmlFor="height">ส่วนสูง (cm)</label> <input type="number" name="height" ref={heightRef} />
<button type="button" onClick={calculateBmi}> คำนวณ </button>
<div className="result"> <p>ค่า BMI คือ: {bmi}</p> <p>ผลลัพธ์</p> <p>{checkBmiResult()}</p> </div> </> )}
export default App
สุดท้าย Source Code เอาไปเรียนรู้เพิ่มเติมครับ
สำหรับใครชอบ Challenge ลองไปทำพวกนี้ดูครับ
- กำหนด min max ของ input ให้ต่ำสุดเท่าไหร่ และสูงสุดเท่าไหร่
- แจ้งเตือน error กรณีใส่ข้อมูลไม่ถูกต้อง
- ไม่ต้องกด ปุ่ม คำนวณ แต่ให้มัน คำนวณทันที ที่พิมพ์ input เลย
- ทำปุ่ม clear หรือ result ข้อมูล
หากใครติดปัญหาตรงไหน สามารถสอบถามมาได้ตลอด ทุกช่องทาง ทั้ง Facebook Page, LINE หรือ Discord ครับ หากตรงไหนผิดพลาด อธิบายเร็วไป หรือไม่เคลียร์ สามารถแนะนำ ติชมได้เช่นกันครับ จะพยายามปรับปรุง และพัฒนาให้มันดีขึ้นครับ
Happy Coding ❤️
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust