Devahoy Logo
PublishedAt

React

[Workshop] ทำแอพคำนวณ BMI ด้วย React.js

[Workshop] ทำแอพคำนวณ BMI ด้วย React.js

สวัสดีครับ 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

Play

Overview

ตัวแอพ ไม่มีอะไรมากครับ เป็นเว็บหน้าเดียว เพื่อคำนวณค่า BMI จากที่ผู้ใช้ทำการใส่ลงไป และแสดงค่า รวมถึงอธิบายผลลัพธ์ออกมาได้ สิ่งที่จะได้จาก Workshop นี้ คือ

  • สร้างโปรเจ็ค React ด้วย Vite + TypeScript
  • การใช้งาน state useState()
  • การใช้ Component การส่ง Props
  • การ handle onChange ค่าจาก input
  • ตัวอย่างการใช้ ref useRef (จะมีสอนในตอนที่ 2 เรื่องของ Form ครับ)

Step 1 - เริ่มต้นสร้างโปรเจ็ค

เราจะสร้างโปรเจ็ค ด้วย Vite นะครับ ด้วยคำสั่งนี้

Terminal window
npm create vite@latest bmi-calculator -- --template react-ts

จากนั้น เปิดโปรเจ็คและทำการติดตั้ง dependencies

Terminal window
cd bmi-calculator
npm install
# start dev server
npm run dev

Step 2 - สร้าง State และ Markup

สร้าง state เพื่อเก็บ weight height และ bmi

1
const [weight, setWeight] = useState(0)
2
const [height, setHeight] = useState(0)
3
const [bmi, setBmi] = useState(0)

ค่า state พวกนี้ จะถุกอัพเดท ก็ต่อเมื่อ input มีการเปลี่ยนแปลงค่า ซึ่ง เราสามารถใช้ event onChange ได้ เวลาที่ input onChange เราก็จะไปเรียก function handleOnChange จากนั้น ใน function นั้นก็ทำการเช็คว่า change จาก input name อะไร ก็ทำการ set state นั้นๆ

1
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
2
const { name, value } = event.target
3
4
if (name === 'weight') {
5
setWeight(Number(value))
6
} else if (name === 'height') {
7
setHeight(Number(value))
8
}
9
}
10
11
return (
12
<label htmlFor="weight">น้ำหนัก (kg)</label>
13
<input type="number" name="weight" onChange={handleOnChange} />
14
15
<label htmlFor="height">ส่วนสูง (cm)</label>
16
<input type="number" name="height" onChange={handleOnChange} />
17
)

Step 3 - การคำนวณ BMI

เราจะใช้สูตรคือ น้ำหนัก / (ส่วนสูง ยกกำลังสอง) ก็ได้เป็นแบบนี้

1
const calculateBmi = () => {
2
// const bmi = weight / ((height / 100) \* (height / 100))
3
4
const bmi = weight / (height / 100) ** 2
5
setBmi(bmi)
6
}

ไฟล์ App.tsx หลังจาก มี markup และ handle onChange และ calculate ก็จะได้เป็นแบบนี้

App.tsx
1
import { useState } from 'react'
2
3
import './App.css'
4
5
function App() {
6
const [weight, setWeight] = useState(0)
7
const [height, setHeight] = useState(0)
8
const [bmi, setBmi] = useState(0)
9
10
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
11
const { name, value } = event.target
12
13
if (name === 'weight') {
14
setWeight(Number(value))
15
} else if (name === 'height') {
16
setHeight(Number(value))
17
}
18
}
19
20
const calculateBmi = () => {
21
// const bmi = weight / ((height / 100) * (height / 100))
22
23
const bmi = weight / (height / 100) ** 2
24
setBmi(bmi)
25
}
26
27
return (
28
<div className="bmi-app">
29
<h1 className="title">BMI Calculator</h1>
30
<p className="subtitle">โปรแกรมคำนวณค่าดัชนีมวลกาย - BMI</p>
31
32
<label htmlFor="weight">น้ำหนัก (kg)</label>
33
<input type="number" name="weight" onChange={handleOnChange} />
34
35
<label htmlFor="height">ส่วนสูง (cm)</label>
36
<input type="number" name="height" onChange={handleOnChange} />
37
38
<button type="button" onClick={calculateBmi}>
39
คำนวณ
40
</button>
41
42
<hr />
43
</div>
44
)
45
}
46
47
export default App

ใน Video ผมลืมพูดไปเรื่องของ event ในฟังค์ชั่น handleOnChange() เนื่องจากเจอ auto suggest จาก Copilot เลยลืม

ตัว event ปกติ เราจะใช้เป็น type React.ChangeEvent และใส่ HTMLInputElement เป็น generic ให้รู้ว่า change event ของ html input นั่นเอง

1
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
2
const { name, value } = event.target
3
4
if (name === 'weight') {
5
setWeight(Number(value))
6
} else if (name === 'height') {
7
setHeight(Number(value))
8
}
9
}

Step 4 - แสดงผลลัพธ์ BMI

ส่วนนี้คือเอาค่า BMI มาแสดงผลลัพธ์ว่าเราผอม อ้วน หรืออยู่ในเกณฑ์ โดยสูตรเราสามารถไปหาดูได้ครับ ว่าเค้าใช้ค่าไหน แต่ในตัวอย่าง ผมให้ Github Copilot มัน auto ให้ ก็เลยได้เป็นแบบนี้

1
const checkBmiResult = () => {
2
if (bmi === 0) return '-'
3
if (bmi < 18.5) return 'อยู่ในเกณฑ์น้ำหนักน้อย / ผอม'
4
if (bmi < 25) return 'อยู่ในเกณฑ์ปกติ (สุขภาพดี)'
5
if (bmi < 30) return 'อยู่ในเกณฑ์ท้วม / โรคอ้วนระดับ 1'
6
if (bmi < 35) return 'อยู่ในเกณฑ์อ้วน / โรคอ้วนระดับ 2'
7
if (bmi >= 35) return 'อยู่ในเกณฑ์อ้วนมาก / โรคอ้วนระดับ 3'
8
}

กำหนดสีให้มัน เพื่อเอาไว้แสดง result แต่ละสี ให้ดูสวยงาม

1
const getResultClass = () => {
2
if (bmi < 18.5) return 'gray'
3
if (bmi < 22.9) return 'green'
4
if (bmi < 24.9) return 'yellow'
5
return 'red'
6
}

ส่วน Result BMI

1
<div className="result">
2
<p>ค่า BMI คือ: {bmi}</p>
3
<p>ผลลัพธ์</p>
4
<p className={getResultClass()}>{checkBmiResult()}</p>
5
</div>

Step 5 - สร้าง Component สำหรับ BMI Result

เราสร้าง Component สำหรับ BMI Result แยกไปอีก component เพื่อให้แยกการทำงานอย่างชัดเจน ตอนนี้ไฟล์ components/BmiResult.tsx จะเป็นแบบนี้

components/BmiResult.tsx
1
interface Props {
2
bmi: number
3
}
4
5
const BmiResult = ({ bmi }: Props) => {
6
const checkBmiResult = () => {
7
if (bmi === 0) return '-'
8
if (bmi < 18.5) return 'อยู่ในเกณฑ์น้ำหนักน้อย / ผอม'
9
if (bmi < 25) return 'อยู่ในเกณฑ์ปกติ (สุขภาพดี)'
10
if (bmi < 30) return 'อยู่ในเกณฑ์ท้วม / โรคอ้วนระดับ 1'
11
if (bmi < 35) return 'อยู่ในเกณฑ์อ้วน / โรคอ้วนระดับ 2'
12
if (bmi >= 35) return 'อยู่ในเกณฑ์อ้วนมาก / โรคอ้วนระดับ 3'
13
}
14
15
const getResultClass = () => {
16
if (bmi < 18.5) return 'gray'
17
if (bmi < 22.9) return 'green'
18
if (bmi < 24.9) return 'yellow'
19
return 'red'
20
}
21
22
return (
23
<div className="result">
24
<p>ค่า BMI คือ: {bmi}</p>
25
<p>ผลลัพธ์</p>
26
<p className={getResultClass()}>{checkBmiResult()}</p>
27
</div>
28
)
29
}
30
31
export default BmiResult

และไฟล์ App.tsx ก็ import BmiResult มาใช้ ผลลัพธ์ก็ได้แบบนี้

App.tsx
1
import { useState } from 'react'
2
import BmiResult from './components/BmiResult'
3
4
import './App.css'
5
6
function App() {
7
const [weight, setWeight] = useState(0)
8
const [height, setHeight] = useState(0)
9
const [bmi, setBmi] = useState(0)
10
11
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
12
const { name, value } = event.target
13
14
if (name === 'weight') {
15
setWeight(Number(value))
16
} else if (name === 'height') {
17
setHeight(Number(value))
18
}
19
}
20
21
const calculateBmi = () => {
22
// const bmi = weight / ((height / 100) * (height / 100))
23
24
const bmi = weight / (height / 100) ** 2
25
setBmi(bmi)
26
}
27
28
return (
29
<div className="bmi-app">
30
<h1 className="title">BMI Calculator</h1>
31
<p className="subtitle">โปรแกรมคำนวณค่าดัชนีมวลกาย - BMI</p>
32
33
<label htmlFor="weight">น้ำหนัก (kg)</label>
34
<input type="number" name="weight" onChange={handleOnChange} />
35
36
<label htmlFor="height">ส่วนสูง (cm)</label>
37
<input type="number" name="height" onChange={handleOnChange} />
38
39
<button type="button" onClick={calculateBmi}>
40
คำนวณ
41
</button>
42
43
<hr />
44
45
<BmiResult bmi={bmi} />
46
</div>
47
)
48
}
49
50
export default App

ปรับแต่ง CSS เล็กๆน้อยๆ เมื่อเราลองดูหน้าเว็บ เว็บเราจะมีหน้าตาสวยงาม แบบนี้

BMI Calculator Website

อ่อ ใน Video ผมยกตัวอย่าง useRef ที่ยังไม่ได้สอนไว้คร่าวๆ เดี๋ยวจะอธิบายเพิ่มเติมในเรื่อง Form นะครับ แต่สำหรับใครอยากใช้ ref ก็ทำได้ครับ แบบนี้

1
import { useRef, useState } from 'react'
2
3
import './App.css'
4
5
function App() {
6
const [bmi, setBmi] = useState(0)
7
8
const heightRef = useRef < HTMLInputElement > null
9
const weightRef = useRef < HTMLInputElement > null
10
11
const calculateBmi = () => {
12
const weight = weightRef.current?.value || 0
13
const height = heightRef.current?.value || 0
14
15
const bmi = Number(weight) / (Number(height) / 100) ** 2
16
setBmi(bmi)
17
}
18
19
const checkBmiResult = () => {
20
return <span>TODO</span>
21
}
22
23
return (
24
<>
25
<h1>BMI Calculator</h1>
26
<p>โปรแกรมคำนวณค่าดัชนีมวลกาย - BMI</p>
27
28
<label htmlFor="weight">น้ำหนัก (kg)</label>
29
<input type="number" name="weight" ref={weightRef} />
30
31
<label htmlFor="height">ส่วนสูง (cm)</label>
32
<input type="number" name="height" ref={heightRef} />
33
34
<button type="button" onClick={calculateBmi}>
35
คำนวณ
36
</button>
37
38
<div className="result">
39
<p>ค่า BMI คือ: {bmi}</p>
40
<p>ผลลัพธ์</p>
41
<p>{checkBmiResult()}</p>
42
</div>
43
</>
44
)
45
}
46
47
export default App

สุดท้าย Source Code เอาไปเรียนรู้เพิ่มเติมครับ

สำหรับใครชอบ Challenge ลองไปทำพวกนี้ดูครับ

  • กำหนด min max ของ input ให้ต่ำสุดเท่าไหร่ และสูงสุดเท่าไหร่
  • แจ้งเตือน error กรณีใส่ข้อมูลไม่ถูกต้อง
  • ไม่ต้องกด ปุ่ม คำนวณ แต่ให้มัน คำนวณทันที ที่พิมพ์ input เลย
  • ทำปุ่ม clear หรือ result ข้อมูล

หากใครติดปัญหาตรงไหน สามารถสอบถามมาได้ตลอด ทุกช่องทาง ทั้ง Facebook Page, LINE หรือ Discord ครับ หากตรงไหนผิดพลาด อธิบายเร็วไป หรือไม่เคลียร์ สามารถแนะนำ ติชมได้เช่นกันครับ จะพยายามปรับปรุง และพัฒนาให้มันดีขึ้นครับ

Happy Coding ❤️

Authors
avatar

Chai Phonbopit

เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust

Related Posts