Efekt Bağımlılıklarını Kaldırma
Bir Efekt yazdığınızda, linter, Efektin okuduğu her reaktif değeri (props ve state gibi) Efektinizin bağımlılıkları listesine dahil ettiğinizi doğrular. Bu, Efektinizin bileşeninizin en son prop’ları ve state’i ile senkronize kalmasını sağlar. Gereksiz bağımlılıklar, Efektinizin çok sık çalışmasına ve hatta sonsuz bir döngü oluşturmasına neden olabilir. Gereksiz bağımlılıkları gözden geçirmek ve Efektlerinizden kaldırmak için bu kılavuzu izleyin.
Bunları öğreneceksiniz
- Sonsuz efekt bağımlılık döngüleri nasıl düzeltilir
- Bir bağımlılığı kaldırmak istediğinizde ne yapmalısınız
- Efektinizden bir değeri ona “tepki vermeden” nasıl okuyabilirsiniz
- Nesne ve fonksiyon bağımlılıklarından nasıl ve neden kaçınılır
- Bağımlılık linterini bastırmak neden tehlikelidir ve bunun yerine ne yapılmalıdır
Bağımlılıklar kod ile eşleşmelidir
Bir Efekt yazdığınızda, ilk olarak Efektinizin yapmasını istediğiniz şeyi nasıl başlatacağınızı ve durduracağınızı belirtirsiniz:
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
// ...
}Ardından, efekt bağımlılıklarını boş bırakırsanız ([]), linter doğru bağımlılıkları önerecektir:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // <-- Buradaki hatayı düzeltin! return <h1>{roomId} odasına hoş geldiniz!</h1>; } export default function App() { const [roomId, setRoomId] = useState('genel'); return ( <> <label> Sohbet odasını seçin:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="genel">Genel</option> <option value="seyehat">Seyehat</option> <option value="müzik">Müzik</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); }
Bunları linterin söylediğine göre doldurun:
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ Tüm bağımlılıklar bildirildi
// ...
}Efektler reaktif değerlere “tepki verir” roomId reaktif bir değer olduğundan (yeniden renderlama nedeniyle değişebilir), linter bunu bir bağımlılık olarak belirttiğinizi doğrular. Eğer roomId farklı bir değer alırsa, React Efektinizi yeniden senkronize edecektir. Bu, sohbetin seçilen odaya bağlı kalmasını ve açılır menüye “tepki vermesini” sağlar:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); return <h1>{roomId} odasına hoş geldiniz!</h1>; } export default function App() { const [roomId, setRoomId] = useState('genel'); return ( <> <label> Sohbet odasını seçin:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="genel">Genel</option> <option value="seyehat">Seyahat</option> <option value="müzik">Müzik</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); }
Bir bağımlılığı kaldırmak için, bunun bir bağımlılık olmadığını kanıtlayın
Efektinizin bağımlılıklarını “seçemeyeceğinize” dikkat edin. Efektinizin kodu tarafından kullanılan her reaktif değer bağımlılık listenizde bildirilmelidir. Bağımlılık listesi çevredeki kod tarafından belirlenir:
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) { // Bu reaktif bir değer
useEffect(() => {
const connection = createConnection(serverUrl, roomId); // Bu efekt o reaktif değeri okur
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ Dolayısıyla, bu reaktif değeri Efektinizin bir bağımlılığı olarak belirtmeniz gerekir
// ...
}Reaktif değerler prop’ları ve doğrudan bileşeninizin içinde bildirilen tüm değişkenleri ve fonksiyonları içerir. roomId reaktif bir değer olduğundan, bağımlılık listesinden kaldıramazsınız. Linter buna izin vermez:
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // 🔴 React Hook useEffect'in eksik bir bağımlılığı var: 'roomId'
// ...
}Ve linter haklı olacaktır! Zaman içinde roomId değişebileceğinden, bu durum kodunuzda bir hataya yol açacaktır.
Bir bağımlılığı kaldırmak için, linter’e bağımlılık olmasına gerek olmadığını “kanıtlayın.” Örneğin, reaktif olmadığını ve yeniden render edildiğinde değişmeyeceğini kanıtlamak için roomId’yi bileşeninizin dışına taşıyabilirsiniz:
const serverUrl = 'https://localhost:1234';
const roomId = 'music'; // Artık reaktif bir değer değil
function ChatRoom() {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // ✅ Tüm bağımlılıklar bildirildi
// ...
}Artık roomId reaktif bir değer olmadığından (ve yeniden render edilmede değişemeyeceğinden), bir bağımlılık olmasına gerek yoktur:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; const roomId = 'müzik'; export default function ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); return <h1>{roomId} odasına hoş geldiniz!</h1>; }
Bu nedenle artık boş ([]) bağımlılık listesi belirtebilirsiniz. Efektiniz gerçekten artık herhangi bir reaktif değere bağlı değildir, bu nedenle gerçekten bileşenin herhangi bir prop’u veya state’i değiştiğinde yeniden çalıştırılması gerekmez.
Bağımlılıkları değiştirmek için kodu değiştirin
İş akışınızda bir düzen fark etmiş olabilirsiniz:
- İlk olarak, Efektinizin kodunu veya reaktif değerlerinizin nasıl beyan edildiğini değiştirirsiniz.
- Ardından, linter’ı takip eder ve bağımlılıkları değiştirdiğiniz kodla eşleşecek şekilde ayarlarsınız.
- Bağımlılıklar listesinden memnun değilseniz, ilk adıma geri dönersiniz (ve kodu tekrar değiştirirsiniz).
Son kısım önemlidir. Bağımlılıkları değiştirmek istiyorsanız, önce çevredeki kodu değiştirin. Bağımlılık listesini Efekt kodunuz tarafından kullanılan tüm reaktif değerlerin bir listesi olarak düşünebilirsiniz. Bu listeye ne koyacağınızı seçmezsiniz. Liste kodunuzu tanımlar. Bağımlılık listesini değiştirmek için kodu değiştirin.
Bu bir denklem çözmek gibi gelebilir. Bir hedefle başlayabilirsiniz (örneğin, bir bağımlılığı kaldırmak için) ve bu hedefle eşleşen kodu “bulmanız” gerekir. Herkes denklem çözmeyi eğlenceli bulmaz ve aynı şey Efekt yazmak için de söylenebilir! Neyse ki, aşağıda deneyebileceğiniz yaygın tariflerin bir listesi var.
Derinlemesine İnceleme
Linteri bastırmak, bulunması ve düzeltilmesi zor olan çok mantıksız hatalara yol açar. İşte bir örnek:
import { useState, useEffect } from 'react'; export default function Timer() { const [count, setCount] = useState(0); const [increment, setIncrement] = useState(1); function onTick() { setCount(count + increment); } useEffect(() => { const id = setInterval(onTick, 1000); return () => clearInterval(id); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> <h1> Sayaç: {count} <button onClick={() => setCount(0)}>Sıfırla</button> </h1> <hr /> <p> Her saniye şu kadar artıyor: <button disabled={increment === 0} onClick={() => { setIncrement(i => i - 1); }}>–</button> <b>{increment}</b> <button onClick={() => { setIncrement(i => i + 1); }}>+</button> </p> </> ); }
Diyelim ki Efekti “sadece montajda” çalıştırmak istediniz. Boş ([]) bağımlılıkların bunu yaptığını okudunuz, bu yüzden linter’ı görmezden gelmeye karar verdiniz ve bağımlılıklar olarak zorla [] belirttiniz.
Bu sayacın her saniye iki düğme ile yapılandırılabilen miktar kadar artması gerekiyordu. Ancak, React’e bu Efektin hiçbir şeye bağlı olmadığı konusunda “yalan söylediğiniz” için, React ilk render’dan itibaren onTick fonksiyonunu sonsuza kadar kullanmaya devam ediyor. Bu render sırasında, count = 0 ve increment = 1 idi. Bu nedenle bu render’daki onTick her zaman her saniye setCount(0 + 1) çağırır ve her zaman 1 görürsünüz. Bunun gibi hatalar birden fazla bileşene yayıldığında düzeltilmesi daha zordur.
Her zaman linter’ı görmezden gelmekten daha iyi bir çözüm vardır! Bu kodu düzeltmek için bağımlılık listesine onTick eklemeniz gerekir. (Aralığın yalnızca bir kez ayarlandığından emin olmak için, onTicki bir Efekt Olayı yapın.)
Bağımlılık lint hatasını bir derleme hatası olarak ele almanızı öneririz. Bunu bastırmazsanız, bu gibi hataları asla görmezsiniz. Bu sayfanın geri kalanı, bu ve diğer durumlar için alternatifleri belgelemektedir.
Gereksiz bağımlılıkları kaldırma
Efektin bağımlılıklarını kodu yansıtacak şekilde her ayarladığınızda, bağımlılık listesine bakın. Bu bağımlılıklardan herhangi biri değiştiğinde Efektin yeniden çalıştırılması mantıklı mı? Bazen cevap “hayır” olabilir:
- Efektinizin farklı bölümlerini farklı koşullar altında yeniden yürütmek isteyebilirsiniz.
- Değişikliklere “tepki vermek” yerine bazı bağımlılıkların yalnızca en son değerini okumak isteyebilirsiniz.
- Bir bağımlılık, bir nesne ya da fonksiyon olduğu için kasıtsız olarak çok sık değişebilir.
Doğru çözümü bulmak için, Efektiniz hakkında birkaç soruyu yanıtlamanız gerekir. Hadi bunların üzerinden geçelim.
Bu kod bir olay yöneticisine taşınmalı mı?
Düşünmeniz gereken ilk şey, bu kodun bir efekt olup olmaması gerektiğidir.
Bir form düşünün. Gönderildiğinde, submitted state değişkenini true olarak ayarlarsınız. Bir POST isteği göndermeniz ve bir bildirim göstermeniz gerekir. Bu mantığı, submitted state’inin true olmasına “tepki veren” bir Efektin içine yerleştirirsiniz:
function Form() {
const [submitted, setSubmitted] = useState(false);
useEffect(() => {
if (submitted) {
// 🔴 Kaçının: Bir Efekt içinde olaya özgü mantık
post('/api/register');
showNotification('Başarıyla Kaydedildi!');
}
}, [submitted]);
function handleSubmit() {
setSubmitted(true);
}
// ...
}Daha sonra, bildirim mesajını mevcut temaya göre şekillendirmek istersiniz, bu nedenle mevcut temayı okursunuz. Bileşen gövdesinde theme bildirildiği için reaktif bir değerdir, bu nedenle onu bir bağımlılık olarak eklersiniz:
function Form() {
const [submitted, setSubmitted] = useState(false);
const theme = useContext(ThemeContext);