รู้จักกับเครื่องมือ State Management พื้นฐาน: useState (React)
จากบทที่แล้ว เราได้เรียนรู้เกี่ยวกับ Scope ของ State หรือขอบเขตของ State ซึ่งแบ่งเป็น Local State และ Global State ในบทนี้ เราจะมาเจาะลึกเครื่องมือพื้นฐานในการจัดการ Local State ใน React นั่นก็คือ useState Hook ครับ
useState Hook คืออะไร?
useState เป็น Hook ที่ React เตรียมไว้ให้เรา เพื่อให้ Component แบบ Functional สามารถเก็บและเปลี่ยนแปลง State ได้ง่ายๆ ครับ ลองนึกภาพว่า useState เป็นเหมือนกล่องวิเศษ ที่เราสามารถใส่ข้อมูลอะไรก็ได้ลงไป และเมื่อข้อมูลในกล่องเปลี่ยนไป React ก็จะรู้ และทำการ render Component นั้นใหม่ เพื่อแสดงผลลัพธ์ที่ถูกต้อง
การใช้งาน useState Hook
การใช้งาน useState นั้นง่ายมากๆ ครับ เราแค่ import Hook นี้มาจาก React แล้วเรียกใช้ภายใน Functional Component ของเรา
import React, { useState } from 'react';
function MyComponent() {
// ประกาศ State variable ชื่อว่า 'count' และ function สำหรับอัพเดทค่า 'count' ชื่อว่า 'setCount'
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default MyComponent;
มาดูกันทีละส่วนนะครับ
import React, { useState } from 'react';: บรรทัดนี้คือการ importuseStateHook จาก Reactconst [count, setCount] = useState(0);: นี่คือบรรทัดสำคัญครับ เรากำลังเรียกใช้useStateHook โดย:count: คือ State variable ที่เราจะใช้เก็บค่า (ในที่นี้คือจำนวนครั้งที่คลิก)setCount: คือ function ที่เราจะใช้เพื่ออัพเดทค่าของcountuseState(0): คือการกำหนดค่าเริ่มต้นของcountเป็น0
<button onClick={() => setCount(count + 1)}>Click me</button>: เมื่อคลิกปุ่ม จะเรียกใช้setCountเพื่ออัพเดทค่าcountโดยบวกเพิ่มไปอีก 1
สรุปง่ายๆ คือ useState จะคืนค่าออกมาเป็น Array ที่มีสมาชิก 2 ตัว: ตัวแรกคือ State variable (ค่าที่เก็บไว้) และตัวที่สองคือ function สำหรับอัพเดท State variable นั้น
การอัพเดท State
การอัพเดท State ทำได้โดยการเรียกใช้ function ที่ useState คืนค่าออกมาให้ (ในตัวอย่างคือ setCount) เมื่อเราเรียกใช้ function นี้ React จะทำการ render Component นั้นใหม่ ทำให้ UI แสดงผลลัพธ์ที่อัพเดท
**ข้อควรจำ:** อย่าพยายามเปลี่ยนแปลงค่า State variable โดยตรง เช่น count = count + 1; เพราะ React จะไม่รู้ว่า State เปลี่ยนไป และจะไม่ทำการ render ใหม่ ทำให้ UI ไม่แสดงผลลัพธ์ที่ถูกต้อง
**กรณีใช้งานจริง:** นอกจากการนับจำนวนครั้งที่คลิกแล้ว เราสามารถใช้ useState เพื่อจัดการ State ได้หลากหลายรูปแบบ เช่น
- การแสดง/ซ่อน Element:
import React, { useState } from 'react';
function ShowHideComponent() {
const [isVisible, setIsVisible] = useState(true);
return (
<div>
<button onClick={() => setIsVisible(!isVisible)}>
{isVisible ? 'Hide' : 'Show'}
</button>
{isVisible && <p>Now you see me!</p>}
</div>
);
}
export default ShowHideComponent;
import React, { useState } from 'react';
function InputComponent() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} />
<p>You typed: {inputValue}</p>
</div>
);
}
export default InputComponent;
ข้อควรระวังในการใช้ useState
- อัพเดท State แบบ Immutability: เมื่อ State เป็น Object หรือ Array, ควรสร้างสำเนาใหม่ก่อนทำการแก้ไข ไม่ควรแก้ไข Object หรือ Array เดิมโดยตรง เพราะอาจทำให้ React ไม่สามารถตรวจจับการเปลี่ยนแปลงได้ ตัวอย่าง:
สำหรับ Array ก็เช่นกัน ควรใช้ methods อย่างimport React, { useState } from 'react'; function ObjectStateComponent() { const [user, setUser] = useState({ name: 'John', age: 30 }); const handleClick = () => { // ไม่ควรทำแบบนี้: user.age = user.age + 1; setUser(user); // ควรทำแบบนี้: สร้างสำเนาใหม่ของ Object setUser({ ...user, age: user.age + 1 }); }; return ( <div> <p>Name: {user.name}</p> <p>Age: {user.age}</p> <button onClick={handleClick}>Increment Age</button> </div> ); } export default ObjectStateComponent;.map(),.filter(), หรือ spread syntax (...) เพื่อสร้างสำเนาใหม่ - Functional Updates: ในบางกรณี ค่า State ใหม่ขึ้นอยู่กับค่า State เก่า การอัพเดท State แบบปกติอาจทำให้เกิดปัญหาได้ (โดยเฉพาะใน Concurrent Mode) React จึงมีวิธีอัพเดท State แบบ Functional Updates โดยการส่ง function เข้าไปใน
setStatefunction นั้น Function นี้จะรับค่า State ปัจจุบันเป็น argument และคืนค่า State ใหม่
การใช้ Functional Updates จะช่วยให้มั่นใจได้ว่าค่า State ที่ใช้ในการคำนวณค่าใหม่นั้นเป็นค่าล่าสุดเสมอimport React, { useState } from 'react'; function CounterComponent() { const [count, setCount] = useState(0); const handleClick = () => { // แทนที่จะทำแบบนี้: setCount(count + 1); // ให้ทำแบบนี้: ใช้ Functional Update setCount(prevCount => prevCount + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Increment</button> </div> ); } export default CounterComponent; - Batch Updates: React อาจทำการ Batch Updates คือรวมการอัพเดท State หลายๆ ครั้งไว้เป็นการ render ครั้งเดียว เพื่อเพิ่มประสิทธิภาพ ถ้าเราต้องการเข้าถึงค่า State ล่าสุดหลังจากการอัพเดททันที อาจต้องใช้
useEffectHook เพื่อตรวจสอบการเปลี่ยนแปลงของ State และทำการ execute code ที่ต้องการ
ในตัวอย่างนี้import React, { useState, useEffect } from 'react'; function BatchUpdateComponent() { const [count, setCount] = useState(0); useEffect(() => { // This effect will run after count is updated console.log("Count updated:", count); }, [count]); // Only run when count changes const handleClick = () => { setCount(count + 1); console.log("Count immediately after setCount:", count); // This might not reflect the updated value yet }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Increment</button> </div> ); } export default BatchUpdateComponent;console.log("Count immediately after setCount:", count);อาจแสดงค่าcountก่อนที่จะถูกอัพเดทจริงๆ ส่วนuseEffectจะทำงานหลังจากที่countถูกอัพเดทแล้ว
สรุป
useState Hook เป็นเครื่องมือที่เรียบง่ายแต่ทรงพลังในการจัดการ Local State ใน React Component หวังว่าบทความนี้จะช่วยให้คุณเข้าใจการใช้งาน useState และสามารถนำไปประยุกต์ใช้กับโปรเจกต์ของคุณได้อย่างมีประสิทธิภาพ ในบทความหน้า เราจะมาทำความรู้จักกับ Context API ซึ่งเป็นอีกทางเลือกหนึ่งในการจัดการ Global State อย่างง่ายครับ