Реагировать на хуки Exhaustive-deps async infinite Loop
У меня есть следующий компонент:
import React, { useState, useEffect } from "react";
const App = () => {
const [data, setData] = useState<null | any[]>(null);
const [checked, setChecked] = useState(false);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
(async () => {
if (data) {
// Could do something else here if data already exsisted
console.log("Data exists already");
}
const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
const json = await ret.json();
setData(json);
setLoading(false);
})();
}, [checked]);
return (
<>
<h1>useEffect Testing {loading && " ⌛"}</h1>
<hr />
<input type="checkbox" checked={checked} onChange={(e) => setChecked(e.target.checked)} />
<pre style={{ fontSize: "0.8em" }}>{JSON.stringify(data)}</pre>
</>
);
};
export default App;
В настоящее время мой if(data)
однако бессмысленно, если бы я хотел проверить текущий data
состояние, а затем запустить асинхронную функцию на основе состояния, в котором eslint (react-hooks / excustive-deps) сообщает мне, что в хуке отсутствуетdata
зависимость, которая есть. Проблема возникает, когда я добавляю данные в список зависимостей, вызывая бесконечный цикл.
Есть идеи, как это решить? Кажется, что это должен быть довольно простой шаблон, однако все, что я нахожу, рекомендуется с использованием расширенногоsetState(prev => prev + 1)
перегрузка, которая мне в этом случае не помогает.
1 ответ
Вы устанавливаете data
а также читая это в эффекте. Это вызовет бесконечный цикл, если вы не остановите его вручную. Вот несколько решений.
Вернуть, если есть данные, вместо их изменения:
useEffect(() => {
setLoading(true);
(async () => {
if (data) {
// Could do something else here if data already exsisted
console.log("Data exists already");
return;
}
const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
const json = await ret.json();
setData(json);
setLoading(false);
})();
}, [checked, data]);
Избавьтесь от зависимости от data
в эффекте, который его устанавливает (что бы я сделал):
useEffect(() => {
setLoading(true);
(async () => {
const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
const json = await ret.json();
setData(json);
setLoading(false);
})();
}, [checked]);
useEffect(() => {
if (data) {
// Could do something else here if data already exsisted
console.log("Data changed and exists!");
}
}, [data]);
Или вы можете вручную сделать что-то, что останавливает бесконечный цикл.
useEffect(() => {
if (loading || data) {
console.log('Do something with loading or data, but do not modify it!')
return;
}
setLoading(true);
(async () => {
const ret = await fetch("https://jsonplaceholder.typicode.com/users?delay=1000", { cache: "no-store" });
const json = await ret.json();
setData(json);
setLoading(false);
})();
}, [checked, data]);