🌐 Detecting your location…

So beheben Sie die Warnung „React Hook useEffect hat eine fehlende Abhängigkeit“.

⏱️7 min read  ·  1,363 words

React Hook useEffect has a missing dependency: 'x'. Either include it or remove the dependency array.Die meisten Entwickler bringen dies mit einem eslint-disable-Kommentar zum Schweigen. Das funktioniert so lange, bis es zu einem Fehler aufgrund veralteter Daten kommt, dessen Entdeckung einen Tag dauert. Die Warnung ist in der Regel richtig und es gibt für jede Situation die richtige Lösung.

Warum die Warnung existiert

Das Abhängigkeitsarray teilt React mit, wann ein Effekt erneut ausgeführt werden soll. Wenn der Effekt einen Wert liest, der nicht aufgeführt ist, behält der Effekt den Wert aus dem Render bei, in dem er zuletzt ausgeführt wurde – ein veralteter Abschluss. Der Code sieht korrekt aus und verhält sich falsch.

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(r => r.json())
      .then(setUser);
  }, []);   // ⚠️ missing dependency: 'userId'

  return <div>{user?.name}</div>;
}

Bei einem leeren Array wird der Abruf einmal ausgeführt. Navigieren Sie von Benutzer 1 zu Benutzer 2 und die Komponente zeigt weiterhin Benutzer 1 an. Die Warnung hat genau dies vorhergesagt.

useEffect(() => {
  fetch(`/api/users/${userId}`)
    .then(r => r.json())
    .then(setUser);
}, [userId]);   // ✅ refetches whenever userId changes

Fix 1: Fügen Sie einfach die Abhängigkeit

hinzu In den meisten Fällen ist die Warnung richtig und das Hinzufügen der Abhängigkeit ist die vollständige Lösung. Tun Sie dies zuerst und untersuchen Sie es nur dann weiter, wenn es eine Schleife verursacht.

Fix 2: Der Effekt wird nach dem Hinzufügen wiederholt

Das Hinzufügen eines Objekts, Arrays oder einer Funktion zum Abhängigkeitsarray führt häufig zu einer Endlosschleife, da diese bei jedem Rendern neu erstellt und anhand von Referenzen verglichen werden.

function Search({ filters }) {
  const [results, setResults] = useState([]);

  useEffect(() => {
    search(filters).then(setResults);
  }, [filters]);   // new object identity every render -> infinite loop
}

Verlassen Sie sich auf die Grundwerte statt auf das Objekt.

useEffect(() => {
  search({ query, category }).then(setResults);
}, [query, category]);   // strings compare by value — stable

Wenn das Objekt tatsächlich von einem Elternteil stammt, prägen Sie es sich dort ein.

// Parent
const filters = useMemo(
  () => ({ query, category }),
  [query, category]
);
return <Search filters={filters} />;

Fix 3: Funktionsabhängigkeiten – useCallback

Eine im Komponentenkörper deklarierte Funktion ist bei jedem Rendern ein neuer Wert. Wenn Sie sie also auflisten, wird der Effekt endlos erneut ausgeführt.

function Dashboard({ userId }) {
  // Recreated every render.
  const loadData = async () => {
    const res = await fetch(`/api/data/${userId}`);
    return res.json();
  };

  useEffect(() => {
    loadData().then(setData);
  }, [loadData]);   // loops
}

Zwei richtige Korrekturen. Wenn die Funktion nur vom Effekt verwendet wird, verschieben Sie sie nach innen – die sauberste Option, da die Abhängigkeit vollständig verschwindet.

useEffect(() => {
  async function loadData() {
    const res = await fetch(`/api/data/${userId}`);
    setData(await res.json());
  }
  loadData();
}, [userId]);   // ✅ only the primitive is a dependency

Wenn die Funktion mit anderen Teilen der Komponente geteilt wird, schließen Sie sie inuseCallback.

const loadData = useCallback(async () => {
  const res = await fetch(`/api/data/${userId}`);
  return res.json();
}, [userId]);

useEffect(() => {
  loadData().then(setData);
}, [loadData]);   // ✅ identity only changes when userId changes

ein Fix 4: Sie benötigen den neuesten Wert, ohne

erneut ausführen zu müssen Manchmal sollte ein Effekt legitimerweise einmal ausgeführt werden, aber der darin enthaltene Rückruf benötigt aktuelle Werte. Ein Verweis enthält einen veränderlichen Wert, der nicht an Abhängigkeiten beteiligt ist.

function Chat({ onMessage }) {
  const onMessageRef = useRef(onMessage);

  // Keep the ref current on every render.
  useEffect(() => {
    onMessageRef.current = onMessage;
  });

  useEffect(() => {
    const socket = new WebSocket('wss://example.com');
    socket.onmessage = (e) => onMessageRef.current(e.data);
    return () => socket.close();
  }, []);   // ✅ connects once, always calls the latest handler
}

Dies ist das richtige Muster für Abonnements, Timer und Ereignis-Listener, bei denen es falsch wäre, bei jedem Requisitenwechsel erneut eine Verbindung herzustellen.

Fix 5: Status von seinem eigenen vorherigen Wert aktualisieren

Das Lesen des Zustands zur Berechnung des nächsten Zustands macht diesen Zustand zu einer Abhängigkeit, die normalerweise eine Schleife verursacht. Das Updater-Formular entfernt die Abhängigkeit.

// Loops: count changes -> effect re-runs -> count changes...
useEffect(() => {
  const id = setInterval(() => setCount(count + 1), 1000);
  return () => clearInterval(id);
}, [count]);

// ✅ No dependency on count at all.
useEffect(() => {
  const id = setInterval(() => setCount(c => c + 1), 1000);
  return () => clearInterval(id);
}, []);

Beim Deaktivieren ist die Regel tatsächlich korrekt

Es gibt einen legitimen Fall: einen echten Mount-Only-Effekt, bei dem Sie absichtlich den Anfangswert und nichts anderes wollen. Die Analyse beim ersten Rendern ist das Standardbeispiel.

useEffect(() => {
  analytics.track('page_view', { page: pageName });
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);   // Intentional: fire once with the initial pageName.

Wenn Sie die Regel deaktivieren, schreiben Sie einen Kommentar, in dem Sie erklären, warum die Auslassung absichtlich erfolgt. Ein bloßer Deaktivierungskommentar ist nicht von jemandem zu unterscheiden, der die Warnung nicht verstanden hat, auch nicht für sich selbst in sechs Monaten.

Brauchen Sie überhaupt einen Effekt?

Ein großer Teil der ausführlichen Warnungen geht auf Effekte zurück, die nicht auftreten sollten. Zwei häufige Fälle:

Abgeleiteter Zustand. Das Berechnen eines Werts aus Requisiten oder Zustand erfordert keinen Effekt.

// Unnecessary effect, extra render, and a dependency warning.
const [fullName, setFullName] = useState('');
useEffect(() => { setFullName(`${first} ${last}`); }, [first, last]);

// ✅ Just calculate it during render.
const fullName = `${first} ${last}`;

Auf ein Ereignis reagieren. Logik, die zu einem Ereignishandler gehört, endet häufig in einem Effektüberwachungszustand, den der Handler festgelegt hat.

// ✅ Do the work where the event happens.
function handleSubmit() {
  submitForm(data);
  analytics.track('form_submitted');
}

Effekte dienen der Synchronisierung mit Systemen außerhalb von React – Netzwerk, Abonnements, DOM, Timer. Wenn nichts Äußeres im Spiel ist, ist ein Effekt wahrscheinlich das falsche Werkzeug.

Entscheidungsleitfaden

Situation Korrigieren Sie
Warnung benennt ein Grundelement Fügen Sie es dem Array
hinzu Objekt oder Array verursachen eine Schleife Abhängig von seinen primitiven Feldern oderuseMemo an der Quelle
Funktion verursacht eine Schleife Verschieben Sie es innerhalb des Effekts oderuseCallback
Benötigt den neuesten Wert, darf nicht erneut ausführen Speichern Sie es in einer Referenz
Der Status leitet sich vom vorherigen Status ab Verwenden Sie die Updater-Funktionsform
Der Wert wird aus Requisiten oder Zustand berechnet Löschen Sie den Effekt und berechnen Sie ihn während des Renderns
Wirklich nur zum Mounten Deaktivieren Sie die Regel mit einer schriftlichen Begründung

Häufig gestellte Fragen

F: Warum wird mein Effekt in der Entwicklung zweimal ausgeführt?
A: Im strengen Modus werden Komponenten absichtlich ein-, aus- und wieder eingehängt, um fehlende Bereinigungsfunktionen aufzudecken. In der Produktion passiert das nicht. Wenn Double-Running etwas kaputt macht, fehlt Ihrem Effekt eine Bereinigung.

F: Kann ich die erschöpfende Deps-Regel einfach deaktivieren?
A: Das können Sie, und Sie werden veraltete Schließungsfehler ausliefern, die extrem schwer aufzuspüren sind. Die Regel erfasst echte Mängel; Lassen Sie es an und beheben Sie die Ursachen.

F: Beeinträchtigt „useCallback Everywhere“ die Leistung?
A: Etwas – es kostet Speicher und Vergleichsarbeit. Verwenden Sie es dort, wo Identitätsstabilität tatsächlich wichtig ist, wie etwa bei Abhängigkeitsarrays und gespeicherten untergeordneten Elementen, und nicht reflexartig bei jeder Funktion.

F: Was ist mit dem React Compiler?
A: Es automatisiert einen Großteil des Auswendiglernens vonuseCallback unduseMemo Führen Sie dies manuell durch, wodurch eine Kategorie dieser Warnungen entfernt wird. Es erspart Ihnen nicht, zu verstehen, von welchen Werten Ihre Wirkung tatsächlich abhängt.

F: Mein Effekt benötigt einen Wert, sollte aber nicht erneut ausgeführt werden, wenn er sich ändert. Ist ein Schiedsrichter ein Hacker?
A: Nein, es ist das dokumentierte Muster für diese Situation. Halten Sie den Verweis in einem separaten Effekt auf dem neuesten Stand und lesen Sie.current Im Inneren ist der langlebige Effekt idiomatisch.

Fazit

Die ausführliche Warnung ist ein Fehlerdetektor und kein Ärgernis. Fügen Sie zuerst die Abhängigkeit hinzu. Wenn es zu einer Schleife kommt, beheben Sie das Identitätsproblem mit den GrundelementenuseMemo, oderuseCallback; Verwenden Sie eine Referenz, wenn Sie aktuelle Werte ohne erneute Ausführung benötigen. Verwenden Sie das Statusaktualisierungsformular, um selbstreferenzielle Schleifen zu unterbrechen. und den Effekt vollständig löschen, wenn der Wert lediglich abgeleitet wird. Reservieren Sie eslint-disable für echte Mount-Only-Effekte und hinterlassen Sie immer einen Kommentar mit der Begründung.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা