Langkau ke kandungan
WANCODE
EN

Effect dan Perangkap Biasa

25 minitPertengahanReact

Dalam pelajaran ini

  • Guna useEffect untuk menyelaraskan dengan sesuatu di luar React (tajuk, pemasa, storage)
  • Pilih dependency array yang betul dan tulis function cleanup
  • Elakkan gelung tak berkesudahan dan effect yang tidak perlu dengan mengira nilai semasa render

Idea utama

Render sepatutnya hanya mengira UI. Apabila anda perlu mencapai sesuatu di luar React — tajuk tab, pemasa, storage pelayar — letakkan kod itu dalam useEffect, yang berjalan selepas React mengemas kini skrin.

Setakat ini semuanya berada di dalam React: state masuk, JSX keluar. Tetapi aplikasi juga perlu berinteraksi dengan perkara yang tidak diurus oleh React: document.title, setInterval, localStorage, sambungan chat. Itu semua side effect, dan tempatnya ialah useEffect.

JSX
import { useEffect } from "react";

useEffect(() => {
  // runs AFTER React has updated the screen
  document.title = "Focus: " + task;
}, [task]); // ← dependency array: re-run when task changes

Dependency array

  • useEffect(fn) — tiada array: berjalan selepas setiap render. Jarang sekali itu yang anda mahu.
  • useEffect(fn, []) — array kosong: berjalan sekali, selepas render pertama (apabila component di-mount).
  • useEffect(fn, [a, b]) — berjalan selepas render pertama dan sekali lagi setiap kali a atau b berubah. Senaraikan setiap nilai dari component yang digunakan oleh effect.

Cleanup (pembersihan)

Jika effect anda memulakan sesuatu — interval, langganan, event listener — return satu function yang menghentikannya. React memanggil cleanup itu sebelum menjalankan effect sekali lagi, dan apabila component itu hilang.

JSX
useEffect(() => {
  if (!running) return;            // nothing to start
  const id = setInterval(() => {
    setSeconds((s) => s + 1);      // updater form: always the latest value
  }, 1000);
  return () => clearInterval(id);  // cleanup: stop this interval
}, [running]);

Kenapa s => s + 1?

Callback interval itu dicipta semasa satu render, jadi seconds di dalamnya tersekat pada nilai render tersebut. setSeconds(seconds + 1) akan asyik menetapkan 1. Bentuk updater meminta nilai terkini daripada React setiap kali.

Dalam projek React sebenar dengan <StrictMode>, React menjalankan setiap effect, cleanup-nya, dan effect itu sekali lagi semasa development. Ini memang disengajakan: cleanup yang tertinggal akan terus kelihatan. (Pratonton WANCode tidak menggunakan StrictMode.)

Perangkap: gelung tak berkesudahan

Menetapkan state di dalam effect menyebabkan render semula. Jika effect berjalan selepas setiap render, ia menetapkan state lagi, yang render lagi… selama-lamanya. React mengesan ini dan memaparkan Maximum update depth exceeded.

Berulang tanpa henti

JSX
useEffect(() => {
  setCount(count + 1); // no array → runs every render
});

Berjalan hanya bila perlu

JSX
useEffect(() => {
  document.title = count + " clicks";
}, [count]); // only when count changes

Mungkin anda tidak perlukan effect

Jika sesuatu nilai boleh dikira daripada props atau state, kira sahaja semasa render. Menyalinnya ke dalam state dengan effect lebih perlahan (render tambahan) dan mudah menjadi tidak selari.

Effect yang tidak perlu

JSX
const [fullName, setFullName] = useState("");
useEffect(() => {
  setFullName(first + " " + last);
}, [first, last]);

Kira sahaja

JSX
const fullName = first + " " + last;

Pratonton mempunyai localStorage emulasi sendiri untuk setiap pelajaran. Ia dikekalkan apabila pratonton dimuat semula, jadi anda boleh lihat nilai yang disimpan kekal — sama seperti pelayar sebenar.

Import useEffect dan tambah effect yang menetapkan document.title kepada Focus: <task> setiap kali task berubah — atau Focus Timer apabila task kosong. Guna [task] sebagai dependency array.

Semakan

  • Tajuk tab mengikut task
  • Task kosong memaparkan Focus Timer
  • Tajuk ditetapkan dalam effect

Uji kefahaman

Q1

Bilakah useEffect(fn, []) berjalan?

Q2

Effect pemasa anda memulakan setInterval tetapi tidak return apa-apa. Apa yang berlaku apabila anda tekan Pause?

Q3

Anda perlukan total = jumlah harga dalam cart (yang merupakan state). Apa yang terbaik?

Apa yang anda pelajari

  • useEffect berjalan selepas render untuk menyelaraskan dengan perkara di luar React: tajuk, pemasa, storage, sambungan.
  • Dependency array menentukan bila ia berjalan semula; senaraikan setiap nilai yang digunakan oleh effect.
  • Return cleanup untuk menghentikan apa sahaja yang anda mulakan (clearInterval, buang listener).
  • Menetapkan state dalam effect tanpa array akan berulang selama-lamanya; nilai yang boleh dikira langsung tidak perlukan effect.
Pratonton

Output konsol daripada kod anda akan dipaparkan di sini.

Langkah 1 daripada 3