useEffect 依赖导致无限循环
useEffect dependency causes infinite loop
我创建了一个我在 App.js
中使用的自定义挂钩
自定义钩子(相关函数为fetchTasks):
export default function useFetch() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [tasks, setTasks] = useState([]);
const fetchTasks = async (url) => {
setLoading(true);
setError(null);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("falied!");
}
const data = await response.json();
const loadedTasks = [];
for (const taskKey in data) {
loadedTasks.push({ id: taskKey, text: data[taskKey].text });
}
setTasks(loadedTasks);
} catch (err) {
console.log(err.message);
}
setLoading(false);
};
return {
loading,
setLoading,
error,
setError,
fetchTasks,
tasks,
};
}
然后在我的 App.js:
function App() {
const { loading, setLoading, error, setError, fetchTasks, tasks } =
useFetch();
useEffect(() => {
console.log("fetching");
fetchTasks(
"https://.....firebaseio.com/tasks.json"
);
}, []);
我的 IDE 建议添加 fetchTasks 函数作为对 useEffect 的依赖。但是一旦我添加它,就会创建一个无限循环。如果我从代码中所示的依赖项中省略它,它将按预期工作,但我知道这是一种不好的做法。那我该怎么办?
而不是 return fetchTasks
函数 return 这个 useCallback
fetchTasksCallback
函数来自 useFetch
钩子,它只创建了一个 fetchTasksCallback
.
const fetchTasksCallback = useCallback(
(url) => {
fetchTasks(url);
},
[],
);
function App() {
const { loading, setLoading, error, setError, fetchTasksCallback, tasks } =
useFetch();
useEffect(() => {
console.log("fetching");
fetchTasksCallback(
"https://.....firebaseio.com/tasks.json"
);
}, [fetchTasksCallback]);
问题是这个fetchTasks
每次创建一个新的实例这样依赖列表感觉有变化并重复useEffect
导致无限循环问题的代码块
因为每次你打电话useFetch()
。 fetchTasks
函数将是 re-created。这会导致引用在每次渲染时发生变化,然后 useEffect()
将检测到依赖项 fetchTasks
是 re-created 并再次执行它,并进行无限循环。
因此,您可以利用 useCallback()
来记忆您的 fetchTasks()
函数,这样引用将保持不变。
import { useCallback } from 'react'
export default function useFetch() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [tasks, setTasks] = useState([]);
const fetchTasks = useCallback(
async (url) => {
setLoading(true);
setError(null);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("falied!");
}
const data = await response.json();
const loadedTasks = [];
for (const taskKey in data) {
loadedTasks.push({ id: taskKey, text: data[taskKey].text });
}
setTasks(loadedTasks);
} catch (err) {
console.log(err.message);
}
setLoading(false);
};,[])
return {
loading,
setLoading,
error,
setError,
fetchTasks,
tasks,
};
}
function App() {
const { loading, setLoading, error, setError, fetchTasks, tasks } =
useFetch();
useEffect(() => {
console.log("fetching");
fetchTasks(
"https://.....firebaseio.com/tasks.json"
);
}, [fetchTasks]);
我创建了一个我在 App.js
中使用的自定义挂钩自定义钩子(相关函数为fetchTasks):
export default function useFetch() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [tasks, setTasks] = useState([]);
const fetchTasks = async (url) => {
setLoading(true);
setError(null);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("falied!");
}
const data = await response.json();
const loadedTasks = [];
for (const taskKey in data) {
loadedTasks.push({ id: taskKey, text: data[taskKey].text });
}
setTasks(loadedTasks);
} catch (err) {
console.log(err.message);
}
setLoading(false);
};
return {
loading,
setLoading,
error,
setError,
fetchTasks,
tasks,
};
}
然后在我的 App.js:
function App() {
const { loading, setLoading, error, setError, fetchTasks, tasks } =
useFetch();
useEffect(() => {
console.log("fetching");
fetchTasks(
"https://.....firebaseio.com/tasks.json"
);
}, []);
我的 IDE 建议添加 fetchTasks 函数作为对 useEffect 的依赖。但是一旦我添加它,就会创建一个无限循环。如果我从代码中所示的依赖项中省略它,它将按预期工作,但我知道这是一种不好的做法。那我该怎么办?
而不是 return fetchTasks
函数 return 这个 useCallback
fetchTasksCallback
函数来自 useFetch
钩子,它只创建了一个 fetchTasksCallback
.
const fetchTasksCallback = useCallback(
(url) => {
fetchTasks(url);
},
[],
);
function App() {
const { loading, setLoading, error, setError, fetchTasksCallback, tasks } =
useFetch();
useEffect(() => {
console.log("fetching");
fetchTasksCallback(
"https://.....firebaseio.com/tasks.json"
);
}, [fetchTasksCallback]);
问题是这个fetchTasks
每次创建一个新的实例这样依赖列表感觉有变化并重复useEffect
导致无限循环问题的代码块
因为每次你打电话useFetch()
。 fetchTasks
函数将是 re-created。这会导致引用在每次渲染时发生变化,然后 useEffect()
将检测到依赖项 fetchTasks
是 re-created 并再次执行它,并进行无限循环。
因此,您可以利用 useCallback()
来记忆您的 fetchTasks()
函数,这样引用将保持不变。
import { useCallback } from 'react'
export default function useFetch() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [tasks, setTasks] = useState([]);
const fetchTasks = useCallback(
async (url) => {
setLoading(true);
setError(null);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("falied!");
}
const data = await response.json();
const loadedTasks = [];
for (const taskKey in data) {
loadedTasks.push({ id: taskKey, text: data[taskKey].text });
}
setTasks(loadedTasks);
} catch (err) {
console.log(err.message);
}
setLoading(false);
};,[])
return {
loading,
setLoading,
error,
setError,
fetchTasks,
tasks,
};
}
function App() {
const { loading, setLoading, error, setError, fetchTasks, tasks } =
useFetch();
useEffect(() => {
console.log("fetching");
fetchTasks(
"https://.....firebaseio.com/tasks.json"
);
}, [fetchTasks]);