โหลดข้อมูลจากระยะไกลด้วย fetch ภายในเอฟเฟกต์ โดยจำลองสถานะการโหลดและข้อผิดพลาดอย่างเป็นระเบียบ
เปิดบทเรียนนี้ใน Kodokonคำร้องขอผ่านเครือข่ายใช้เวลาและอาจล้มเหลว: ส่วนต่อประสานของคุณต้องสะท้อนความเป็นจริงเหล่านั้น ธรรมเนียมมืออาชีพคือการติดตาม state ที่แตกต่างกันสามส่วน: ข้อมูล (data) ที่ได้รับ, บูลีน สถานะโหลด (loading), และ ข้อผิดพลาด (error) ที่อาจเกิดขึ้น คำร้องขอจะอยู่ภายใน useEffect เพราะการติดต่อเซิร์ฟเวอร์ถือเป็นผลข้างเคียง
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("https://api.example.com/users")
.then((res) => {
if (!res.ok) throw new Error("HTTP " + res.status);
return res.json();
})
.then((data) => setUsers(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);ในการเรนเดอร์ ให้จัดการกรณีต่าง ๆ ตามลำดับ: สถานะโหลดก่อน แล้วจึงข้อผิดพลาด และสุดท้ายคือข้อมูล early return เหล่านี้ช่วยให้โค้ดอ่านง่ายและรับประกันว่าผู้ใช้จะเห็นบางสิ่งที่สอดคล้องกันเสมอ: ตัวบ่งชี้การรอ ข้อความแจ้งความล้มเหลว หรือรายการที่คาดหวัง
if (loading) return <p>Loading…</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);กับดักสุดท้าย: หาก dependency เปลี่ยน (เช่น userId) คำร้องขอใหม่จะถูกส่งออกไปในขณะที่คำร้องขอเก่าอาจยังค้างอยู่ระหว่างทาง หากคำร้องขอเก่าตอบกลับมาทีหลัง มันจะเขียนทับข้อมูลใหม่ มาตรการรับมือคลาสสิก: แฟล็ก ignore ที่ถูกตั้งค่าเป็น true โดยฟังก์ชัน cleanup เพื่อทิ้งการตอบกลับที่เก่าค้าง
useEffect(() => {
let ignore = false;
setLoading(true);
fetch("/api/users/" + userId)
.then((res) => res.json())
.then((data) => {
if (!ignore) setUser(data);
})
.finally(() => {
if (!ignore) setLoading(false);
});
return () => {
ignore = true;
};
}, [userId]);catch ไม่เคยทำงาน ทำไม?ignore ที่ถูกตั้งค่าเป็น true ใน cleanup ของเอฟเฟกต์ มีไว้ใช้เพื่ออะไร?