Kodokon kodokon.com

การเรียก API: fetch สถานะโหลด และข้อผิดพลาด

โหลดข้อมูลจากระยะไกลด้วย fetch ภายในเอฟเฟกต์ โดยจำลองสถานะการโหลดและข้อผิดพลาดอย่างเป็นระเบียบ

10 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

คำร้องขอผ่านเครือข่ายใช้เวลาและอาจล้มเหลว: ส่วนต่อประสานของคุณต้องสะท้อนความเป็นจริงเหล่านั้น ธรรมเนียมมืออาชีพคือการติดตาม state ที่แตกต่างกันสามส่วน: ข้อมูล (data) ที่ได้รับ, บูลีน สถานะโหลด (loading), และ ข้อผิดพลาด (error) ที่อาจเกิดขึ้น คำร้องขอจะอยู่ภายใน useEffect เพราะการติดต่อเซิร์ฟเวอร์ถือเป็นผลข้างเคียง

JSX
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));
}, []);
สาม state สำหรับหนึ่งคำร้องขอ: data, loading, error

ในการเรนเดอร์ ให้จัดการกรณีต่าง ๆ ตามลำดับ: สถานะโหลดก่อน แล้วจึงข้อผิดพลาด และสุดท้ายคือข้อมูล early return เหล่านี้ช่วยให้โค้ดอ่านง่ายและรับประกันว่าผู้ใช้จะเห็นบางสิ่งที่สอดคล้องกันเสมอ: ตัวบ่งชี้การรอ ข้อความแจ้งความล้มเหลว หรือรายการที่คาดหวัง

JSX
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>
);
early return: แสดงเพียงกรณีเดียวในแต่ละครั้ง

กับดักสุดท้าย: หาก dependency เปลี่ยน (เช่น userId) คำร้องขอใหม่จะถูกส่งออกไปในขณะที่คำร้องขอเก่าอาจยังค้างอยู่ระหว่างทาง หากคำร้องขอเก่าตอบกลับมาทีหลัง มันจะเขียนทับข้อมูลใหม่ มาตรการรับมือคลาสสิก: แฟล็ก ignore ที่ถูกตั้งค่าเป็น true โดยฟังก์ชัน cleanup เพื่อทิ้งการตอบกลับที่เก่าค้าง

JSX
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]);
การตอบกลับที่เก่าค้างทุกรายการถูกทิ้งด้วยแฟล็กนี้

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. ทำไมจึงติดตามสาม state (data, loading, error) สำหรับหนึ่งคำร้องขอ?
    • เพราะ fetch ต้องการตัวแปรทั้งสามนี้จึงจะทำงานได้
    • เพื่อให้ส่วนต่อประสานสะท้อนแต่ละช่วง: การรอ ความล้มเหลว หรือความสำเร็จ
    • เพื่อป้องกันไม่ให้ React ยิงคำร้องขอซ้ำในทุกการเรนเดอร์
  2. API ของคุณตอบกลับด้วยสถานะ 500 แต่ catch ไม่เคยทำงาน ทำไม?
    • fetch ปฏิเสธ Promise เฉพาะเมื่อเครือข่ายล้มเหลวเท่านั้น ไม่ใช่สำหรับสถานะข้อผิดพลาด HTTP
    • catch ไม่ทำงานภายใน useEffect
    • เซิร์ฟเวอร์ต้องส่ง header พิเศษเพื่อกระตุ้น catch
  3. แฟล็ก ignore ที่ถูกตั้งค่าเป็น true ใน cleanup ของเอฟเฟกต์ มีไว้ใช้เพื่ออะไร?
    • เพื่อยกเลิกคำร้องขอ HTTP ที่กำลังค้างอยู่ในฝั่งเซิร์ฟเวอร์
    • เพื่อป้องกันไม่ให้ React รันเอฟเฟกต์ซ้ำ
    • เพื่อทิ้งการตอบกลับของคำร้องขอที่เก่าค้างไปแล้ว