Kodokon kodokon.com

useEffect: เอฟเฟกต์ dependencies และ cleanup

ซิงโครไนซ์คอมโพเนนต์ของคุณกับโลกภายนอกด้วย useEffect โดยเชี่ยวชาญเรื่อง dependencies และ cleanup

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

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

คอมโพเนนต์ React คำนวณ JSX จาก props และ state สิ่งใดที่อยู่นอกขอบเขตนั้น - การเปลี่ยน title ของเอกสาร การเริ่มตัวจับเวลา การสมัครรับอีเวนต์ของเบราว์เซอร์ - ถือเป็น ผลข้างเคียง (side effect) useEffect รันโค้ดนั้น หลังจาก การเรนเดอร์ โดยไม่บล็อกการแสดงผล และซิงโครไนซ์ใหม่เมื่อค่าบางค่าเปลี่ยน

JSX
import { useEffect } from "react";

function CartTitle({ count }) {
  useEffect(() => {
    document.title = `Cart (${count})`;
  }, [count]);

  return <p>Items: {count}</p>;
}
เอฟเฟกต์จะรันใหม่เฉพาะเมื่อ count เปลี่ยน

อาร์เรย์ dependencies ควบคุมว่าเอฟเฟกต์จะรันบ่อยแค่ไหน [count]: เอฟเฟกต์รันใหม่หลังทุกการเรนเดอร์ที่ count เปลี่ยน []: เอฟเฟกต์รันเพียงครั้งเดียว หลังการเรนเดอร์ครั้งแรก ไม่มีอาร์เรย์: เอฟเฟกต์รันใหม่หลัง ทุก การเรนเดอร์ ซึ่งมักไม่ใช่สิ่งที่คุณต้องการ กฎทอง: ทุกค่าของคอมโพเนนต์ที่ใช้ภายในเอฟเฟกต์ต้องปรากฏในอาร์เรย์

JSX
import { useEffect, useState } from "react";

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setSeconds((s) => s + 1);
    }, 1000);

    return () => clearInterval(id);
  }, []);

  return <p>Elapsed: {seconds} s</p>;
}
หากไม่มี clearInterval ตัวจับเวลาจะอยู่นานกว่าคอมโพเนนต์

ฟังก์ชันที่เอฟเฟกต์คืนค่ากลับมาคือฟังก์ชัน cleanup React เรียกมันก่อนการรันเอฟเฟกต์รอบใหม่ทุกครั้ง แล้วเรียกอีกครั้งหนึ่งเป็นครั้งสุดท้ายเมื่อคอมโพเนนต์ถูกถอด (unmount) มันคือสิ่งที่ป้องกันการรั่วไหล: ตัวจับเวลาที่ถูกทิ้ง listener ที่ซ้อนทับกัน การสมัครรับที่ไม่เคยถูกยกเลิก ทุกเอฟเฟกต์ที่ “เปิด” อะไรบางอย่างต้องปิดมันอีกครั้ง

JSX
useEffect(() => {
  function onResize() {
    setWidth(window.innerWidth);
  }
  window.addEventListener("resize", onResize);

  return () => {
    window.removeEventListener("resize", onResize);
  };
}, []);
สมัครรับอีเวนต์ resize และยกเลิกเมื่อ unmount

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

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

  1. เมื่อใช้ useEffect(fn, []) ฟังก์ชัน fn จะถูกรันเมื่อใด?
    • ก่อนทุกการเรนเดอร์ของคอมโพเนนต์
    • หลังการเรนเดอร์ครั้งแรกเท่านั้น
    • ทุกครั้งที่ state อัปเดต
  2. ฟังก์ชัน cleanup ที่เอฟเฟกต์คืนค่ากลับมาจะถูกเรียกเมื่อใด?
    • เฉพาะเมื่อคอมโพเนนต์ถูก unmount เท่านั้น
    • ก่อนการรันเอฟเฟกต์รอบใหม่ทุกครั้งและตอน unmount
    • ก่อนการเรนเดอร์ครั้งแรกของคอมโพเนนต์เท่านั้น
    • ไม่มีการเรียกอัตโนมัติ: คุณต้องเรียกเอง
  3. เอฟเฟกต์อ่าน userId แต่อาร์เรย์ dependencies คือ [] ปัญหาคืออะไร?
    • เอฟเฟกต์จะไม่รันใหม่เมื่อ userId เปลี่ยนและจะถือค่าเก่าค้างไว้
    • React จะโยนข้อผิดพลาดในการเรนเดอร์ครั้งแรก
    • เอฟเฟกต์จะรันซ้ำเป็นลูปไม่รู้จบ